early-access version 2281
This commit is contained in:
302
externals/SDL/src/video/cocoa/SDL_cocoawindow.m
vendored
302
externals/SDL/src/video/cocoa/SDL_cocoawindow.m
vendored
@@ -55,9 +55,21 @@
|
||||
#ifndef MAC_OS_X_VERSION_10_12
|
||||
#define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask
|
||||
#endif
|
||||
#ifndef NSAppKitVersionNumber10_14
|
||||
#define NSAppKitVersionNumber10_14 1671
|
||||
#ifndef NSAppKitVersionNumber10_13_2
|
||||
#define NSAppKitVersionNumber10_13_2 1561.2
|
||||
#endif
|
||||
#ifndef NSAppKitVersionNumber10_14
|
||||
#define NSAppKitVersionNumber10_14 1671
|
||||
#endif
|
||||
|
||||
@interface NSWindow (SDL)
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101000 /* Added in the 10.10 SDK */
|
||||
@property (readonly) NSRect contentLayoutRect;
|
||||
#endif
|
||||
|
||||
/* This is available as of 10.13.2, but isn't in public headers */
|
||||
@property (nonatomic) NSRect mouseConfinementRect;
|
||||
@end
|
||||
|
||||
@interface SDLWindow : NSWindow <NSDraggingDestination>
|
||||
/* These are needed for borderless/fullscreen windows */
|
||||
@@ -322,6 +334,119 @@ SetWindowStyle(SDL_Window * window, NSUInteger style)
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
ShouldAdjustCoordinatesForGrab(SDL_Window * window)
|
||||
{
|
||||
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
|
||||
|
||||
if (!data || [data->listener isMovingOrFocusClickPending]) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (!(window->flags & SDL_WINDOW_INPUT_FOCUS)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if ((window->flags & SDL_WINDOW_MOUSE_GRABBED) || (window->mouse_rect.w > 0 && window->mouse_rect.h > 0)) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
AdjustCoordinatesForGrab(SDL_Window * window, int x, int y, CGPoint *adjusted)
|
||||
{
|
||||
if (window->mouse_rect.w > 0 && window->mouse_rect.h > 0) {
|
||||
SDL_Rect window_rect;
|
||||
SDL_Rect mouse_rect;
|
||||
|
||||
window_rect.x = 0;
|
||||
window_rect.y = 0;
|
||||
window_rect.w = window->w;
|
||||
window_rect.h = window->h;
|
||||
|
||||
if (SDL_IntersectRect(&window->mouse_rect, &window_rect, &mouse_rect)) {
|
||||
int left = window->x + mouse_rect.x;
|
||||
int right = left + mouse_rect.w - 1;
|
||||
int top = window->y + mouse_rect.y;
|
||||
int bottom = top + mouse_rect.h - 1;
|
||||
if (x < left || x > right || y < top || y > bottom) {
|
||||
adjusted->x = SDL_clamp(x, left, right);
|
||||
adjusted->y = SDL_clamp(y, top, bottom);
|
||||
return SDL_TRUE;
|
||||
}
|
||||
return SDL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0) {
|
||||
int left = window->x;
|
||||
int right = left + window->w - 1;
|
||||
int top = window->y;
|
||||
int bottom = top + window->h - 1;
|
||||
if (x < left || x > right || y < top || y > bottom) {
|
||||
adjusted->x = SDL_clamp(x, left, right);
|
||||
adjusted->y = SDL_clamp(y, top, bottom);
|
||||
return SDL_TRUE;
|
||||
}
|
||||
}
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
Cocoa_UpdateClipCursor(SDL_Window * window)
|
||||
{
|
||||
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
|
||||
|
||||
if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_13_2) {
|
||||
NSWindow *nswindow = data->nswindow;
|
||||
SDL_Rect mouse_rect;
|
||||
|
||||
SDL_zero(mouse_rect);
|
||||
|
||||
if (ShouldAdjustCoordinatesForGrab(window)) {
|
||||
SDL_Rect window_rect;
|
||||
|
||||
window_rect.x = 0;
|
||||
window_rect.y = 0;
|
||||
window_rect.w = window->w;
|
||||
window_rect.h = window->h;
|
||||
|
||||
if (window->mouse_rect.w > 0 && window->mouse_rect.h > 0) {
|
||||
SDL_IntersectRect(&window->mouse_rect, &window_rect, &mouse_rect);
|
||||
}
|
||||
|
||||
if ((window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0 &&
|
||||
SDL_RectEmpty(&mouse_rect)) {
|
||||
SDL_memcpy(&mouse_rect, &window_rect, sizeof(mouse_rect));
|
||||
}
|
||||
}
|
||||
|
||||
if (SDL_RectEmpty(&mouse_rect)) {
|
||||
nswindow.mouseConfinementRect = NSZeroRect;
|
||||
} else {
|
||||
NSRect rect;
|
||||
rect.origin.x = mouse_rect.x;
|
||||
rect.origin.y = [nswindow contentLayoutRect].size.height - mouse_rect.y - mouse_rect.h;
|
||||
rect.size.width = mouse_rect.w;
|
||||
rect.size.height = mouse_rect.h;
|
||||
nswindow.mouseConfinementRect = rect;
|
||||
}
|
||||
} else {
|
||||
/* Move the cursor to the nearest point in the window */
|
||||
if (ShouldAdjustCoordinatesForGrab(window)) {
|
||||
int x, y;
|
||||
CGPoint cgpoint;
|
||||
|
||||
SDL_GetGlobalMouseState(&x, &y);
|
||||
if (AdjustCoordinatesForGrab(window, x, y, &cgpoint)) {
|
||||
Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y);
|
||||
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@implementation Cocoa_WindowListener
|
||||
|
||||
@@ -352,6 +477,7 @@ SetWindowStyle(SDL_Window * window, NSUInteger style)
|
||||
[center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:window];
|
||||
[center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window];
|
||||
[center addObserver:self selector:@selector(windowDidChangeBackingProperties:) name:NSWindowDidChangeBackingPropertiesNotification object:window];
|
||||
[center addObserver:self selector:@selector(windowDidChangeScreenProfile:) name:NSWindowDidChangeScreenProfileNotification object:window];
|
||||
[center addObserver:self selector:@selector(windowWillEnterFullScreen:) name:NSWindowWillEnterFullScreenNotification object:window];
|
||||
[center addObserver:self selector:@selector(windowDidEnterFullScreen:) name:NSWindowDidEnterFullScreenNotification object:window];
|
||||
[center addObserver:self selector:@selector(windowWillExitFullScreen:) name:NSWindowWillExitFullScreenNotification object:window];
|
||||
@@ -483,6 +609,7 @@ SetWindowStyle(SDL_Window * window, NSUInteger style)
|
||||
[center removeObserver:self name:NSWindowDidBecomeKeyNotification object:window];
|
||||
[center removeObserver:self name:NSWindowDidResignKeyNotification object:window];
|
||||
[center removeObserver:self name:NSWindowDidChangeBackingPropertiesNotification object:window];
|
||||
[center removeObserver:self name:NSWindowDidChangeScreenProfileNotification object:window];
|
||||
[center removeObserver:self name:NSWindowWillEnterFullScreenNotification object:window];
|
||||
[center removeObserver:self name:NSWindowDidEnterFullScreenNotification object:window];
|
||||
[center removeObserver:self name:NSWindowWillExitFullScreenNotification object:window];
|
||||
@@ -513,12 +640,12 @@ SetWindowStyle(SDL_Window * window, NSUInteger style)
|
||||
return isMoving || (focusClickPending != 0);
|
||||
}
|
||||
|
||||
-(void) setFocusClickPending:(int) button
|
||||
-(void) setFocusClickPending:(NSInteger) button
|
||||
{
|
||||
focusClickPending |= (1 << button);
|
||||
}
|
||||
|
||||
-(void) clearFocusClickPending:(int) button
|
||||
-(void) clearFocusClickPending:(NSInteger) button
|
||||
{
|
||||
if ((focusClickPending & (1 << button)) != 0) {
|
||||
focusClickPending &= ~(1 << button);
|
||||
@@ -567,6 +694,8 @@ SetWindowStyle(SDL_Window * window, NSUInteger style)
|
||||
}
|
||||
|
||||
mouse->SetRelativeMouseMode(SDL_TRUE);
|
||||
} else {
|
||||
Cocoa_UpdateClipCursor(_data->window);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -665,6 +794,10 @@ SetWindowStyle(SDL_Window * window, NSUInteger style)
|
||||
|
||||
- (void)windowDidMiniaturize:(NSNotification *)aNotification
|
||||
{
|
||||
if (focusClickPending) {
|
||||
focusClickPending = 0;
|
||||
[self onMovingOrFocusClickPendingStateCleared];
|
||||
}
|
||||
SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
|
||||
}
|
||||
|
||||
@@ -750,6 +883,11 @@ SetWindowStyle(SDL_Window * window, NSUInteger style)
|
||||
}
|
||||
}
|
||||
|
||||
- (void)windowDidChangeScreenProfile:(NSNotification *)aNotification
|
||||
{
|
||||
SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_ICCPROF_CHANGED, 0, 0);
|
||||
}
|
||||
|
||||
- (void)windowWillEnterFullScreen:(NSNotification *)aNotification
|
||||
{
|
||||
SDL_Window *window = _data->window;
|
||||
@@ -1012,16 +1150,43 @@ SetWindowStyle(SDL_Window * window, NSUInteger style)
|
||||
return NO; /* not a special area, carry on. */
|
||||
}
|
||||
|
||||
static int
|
||||
Cocoa_SendMouseButtonClicks(SDL_Mouse * mouse, NSEvent *theEvent, SDL_Window * window, const Uint8 state, const Uint8 button)
|
||||
{
|
||||
const SDL_MouseID mouseID = mouse->mouseID;
|
||||
const int clicks = (int) [theEvent clickCount];
|
||||
SDL_Window *focus = SDL_GetKeyboardFocus();
|
||||
int rc;
|
||||
|
||||
// macOS will send non-left clicks to background windows without raising them, so we need to
|
||||
// temporarily adjust the mouse position when this happens, as `mouse` will be tracking
|
||||
// the position in the currently-focused window. We don't (currently) send a mousemove
|
||||
// event for the background window, this just makes sure the button is reported at the
|
||||
// correct position in its own event.
|
||||
if ( focus && ([theEvent window] == ((SDL_WindowData *) focus->driverdata)->nswindow) ) {
|
||||
rc = SDL_SendMouseButtonClicks(window, mouseID, state, button, clicks);
|
||||
} else {
|
||||
const int orig_x = mouse->x;
|
||||
const int orig_y = mouse->y;
|
||||
const NSPoint point = [theEvent locationInWindow];
|
||||
mouse->x = (int) point.x;
|
||||
mouse->y = (int) (window->h - point.y);
|
||||
rc = SDL_SendMouseButtonClicks(window, mouseID, state, button, clicks);
|
||||
mouse->x = orig_x;
|
||||
mouse->y = orig_y;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent *)theEvent
|
||||
{
|
||||
const SDL_Mouse *mouse = SDL_GetMouse();
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
if (!mouse) {
|
||||
return;
|
||||
}
|
||||
|
||||
const SDL_MouseID mouseID = mouse->mouseID;
|
||||
int button;
|
||||
int clicks;
|
||||
|
||||
/* Ignore events that aren't inside the client area (i.e. title bar.) */
|
||||
if ([theEvent window]) {
|
||||
@@ -1058,9 +1223,7 @@ SetWindowStyle(SDL_Window * window, NSUInteger style)
|
||||
break;
|
||||
}
|
||||
|
||||
clicks = (int) [theEvent clickCount];
|
||||
|
||||
SDL_SendMouseButtonClicks(_data->window, mouseID, SDL_PRESSED, button, clicks);
|
||||
Cocoa_SendMouseButtonClicks(mouse, theEvent, _data->window, SDL_PRESSED, button);
|
||||
}
|
||||
|
||||
- (void)rightMouseDown:(NSEvent *)theEvent
|
||||
@@ -1075,14 +1238,12 @@ SetWindowStyle(SDL_Window * window, NSUInteger style)
|
||||
|
||||
- (void)mouseUp:(NSEvent *)theEvent
|
||||
{
|
||||
const SDL_Mouse *mouse = SDL_GetMouse();
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
if (!mouse) {
|
||||
return;
|
||||
}
|
||||
|
||||
const SDL_MouseID mouseID = mouse->mouseID;
|
||||
int button;
|
||||
int clicks;
|
||||
|
||||
if ([self processHitTest:theEvent]) {
|
||||
SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_HIT_TEST, 0, 0);
|
||||
@@ -1109,9 +1270,7 @@ SetWindowStyle(SDL_Window * window, NSUInteger style)
|
||||
break;
|
||||
}
|
||||
|
||||
clicks = (int) [theEvent clickCount];
|
||||
|
||||
SDL_SendMouseButtonClicks(_data->window, mouseID, SDL_RELEASED, button, clicks);
|
||||
Cocoa_SendMouseButtonClicks(mouse, theEvent, _data->window, SDL_RELEASED, button);
|
||||
}
|
||||
|
||||
- (void)rightMouseUp:(NSEvent *)theEvent
|
||||
@@ -1149,27 +1308,15 @@ SetWindowStyle(SDL_Window * window, NSUInteger style)
|
||||
x = (int)point.x;
|
||||
y = (int)(window->h - point.y);
|
||||
|
||||
if (window->flags & SDL_WINDOW_MOUSE_GRABBED) {
|
||||
if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
} else if (x >= window->w) {
|
||||
x = window->w - 1;
|
||||
}
|
||||
if (y < 0) {
|
||||
y = 0;
|
||||
} else if (y >= window->h) {
|
||||
y = window->h - 1;
|
||||
}
|
||||
|
||||
CGPoint cgpoint;
|
||||
cgpoint.x = window->x + x;
|
||||
cgpoint.y = window->y + y;
|
||||
|
||||
if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_13_2) {
|
||||
/* Mouse grab is taken care of by the confinement rect */
|
||||
} else {
|
||||
CGPoint cgpoint;
|
||||
if (ShouldAdjustCoordinatesForGrab(window) &&
|
||||
AdjustCoordinatesForGrab(window, window->x + x, window->y + y, &cgpoint)) {
|
||||
Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y);
|
||||
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
|
||||
CGAssociateMouseAndMouseCursorPosition(YES);
|
||||
|
||||
Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1200,7 +1347,18 @@ SetWindowStyle(SDL_Window * window, NSUInteger style)
|
||||
{
|
||||
/* probably a MacBook trackpad; make this look like a synthesized event.
|
||||
This is backwards from reality, but better matches user expectations. */
|
||||
const BOOL istrackpad = ([theEvent subtype] == NSEventSubtypeMouseEvent);
|
||||
BOOL istrackpad = NO;
|
||||
@try {
|
||||
istrackpad = ([theEvent subtype] == NSEventSubtypeMouseEvent);
|
||||
}
|
||||
@catch (NSException *e) {
|
||||
/* if NSEvent type doesn't have subtype, such as NSEventTypeBeginGesture on
|
||||
* macOS 10.5 to 10.10, then NSInternalInconsistencyException is thrown.
|
||||
* This still prints a message to terminal so catching it's not an ideal solution.
|
||||
*
|
||||
* *** Assertion failure in -[NSEvent subtype]
|
||||
*/
|
||||
}
|
||||
|
||||
NSSet *touches = [theEvent touchesMatchingPhase:NSTouchPhaseAny inView:nil];
|
||||
const SDL_TouchID touchID = istrackpad ? SDL_MOUSE_TOUCHID : (SDL_TouchID)(intptr_t)[[touches anyObject] device];
|
||||
@@ -1251,7 +1409,18 @@ SetWindowStyle(SDL_Window * window, NSUInteger style)
|
||||
|
||||
/* probably a MacBook trackpad; make this look like a synthesized event.
|
||||
This is backwards from reality, but better matches user expectations. */
|
||||
const BOOL istrackpad = ([theEvent subtype] == NSEventSubtypeMouseEvent);
|
||||
BOOL istrackpad = NO;
|
||||
@try {
|
||||
istrackpad = ([theEvent subtype] == NSEventSubtypeMouseEvent);
|
||||
}
|
||||
@catch (NSException *e) {
|
||||
/* if NSEvent type doesn't have subtype, such as NSEventTypeBeginGesture on
|
||||
* macOS 10.5 to 10.10, then NSInternalInconsistencyException is thrown.
|
||||
* This still prints a message to terminal so catching it's not an ideal solution.
|
||||
*
|
||||
* *** Assertion failure in -[NSEvent subtype]
|
||||
*/
|
||||
}
|
||||
|
||||
for (NSTouch *touch in touches) {
|
||||
const SDL_TouchID touchId = istrackpad ? SDL_MOUSE_TOUCHID : (SDL_TouchID)(intptr_t)[touch device];
|
||||
@@ -1981,6 +2150,42 @@ Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
Cocoa_GetWindowICCProfile(_THIS, SDL_Window * window, size_t * size)
|
||||
{
|
||||
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
|
||||
NSWindow *nswindow = data->nswindow;
|
||||
NSScreen *screen = [nswindow screen];
|
||||
NSData* iccProfileData = nil;
|
||||
void* retIccProfileData = NULL;
|
||||
|
||||
if (screen == nil) {
|
||||
SDL_SetError("Could not get screen of window.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ([screen colorSpace] == nil) {
|
||||
SDL_SetError("Could not get colorspace information of screen.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
iccProfileData = [[screen colorSpace] ICCProfileData];
|
||||
if (iccProfileData == nil) {
|
||||
SDL_SetError("Could not get ICC profile data.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retIccProfileData = SDL_malloc([iccProfileData length]);
|
||||
if (!retIccProfileData) {
|
||||
SDL_OutOfMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
[iccProfileData getBytes:retIccProfileData length:[iccProfileData length]];
|
||||
*size = [iccProfileData length];
|
||||
return retIccProfileData;
|
||||
}
|
||||
|
||||
int
|
||||
Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
|
||||
{
|
||||
@@ -2005,27 +2210,20 @@ Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
Cocoa_SetWindowMouseRect(_THIS, SDL_Window * window)
|
||||
{
|
||||
Cocoa_UpdateClipCursor(window);
|
||||
}
|
||||
|
||||
void
|
||||
Cocoa_SetWindowMouseGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
|
||||
{
|
||||
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
|
||||
|
||||
/* Move the cursor to the nearest point in the window */
|
||||
if (grabbed && data && ![data->listener isMovingOrFocusClickPending]) {
|
||||
int x, y;
|
||||
CGPoint cgpoint;
|
||||
Cocoa_UpdateClipCursor(window);
|
||||
|
||||
SDL_GetMouseState(&x, &y);
|
||||
cgpoint.x = window->x + x;
|
||||
cgpoint.y = window->y + y;
|
||||
|
||||
Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y);
|
||||
|
||||
DLog("Returning cursor to (%g, %g)", cgpoint.x, cgpoint.y);
|
||||
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
|
||||
}
|
||||
|
||||
if ( data && (window->flags & SDL_WINDOW_FULLSCREEN) ) {
|
||||
if (data && (window->flags & SDL_WINDOW_FULLSCREEN)) {
|
||||
if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_INPUT_FOCUS)
|
||||
&& ![data->listener isInFullscreenSpace]) {
|
||||
/* OpenGL is rendering to the window, so make it visible! */
|
||||
|
||||
Reference in New Issue
Block a user