summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamouse.m
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
committer3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
commit5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch)
tree8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamouse.m
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamouse.m')
-rw-r--r--contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamouse.m591
1 files changed, 591 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamouse.m b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamouse.m
new file mode 100644
index 0000000..530ca0c
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamouse.m
@@ -0,0 +1,591 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "SDL_internal.h"
22
23#ifdef SDL_VIDEO_DRIVER_COCOA
24
25#include "SDL_cocoamouse.h"
26#include "SDL_cocoavideo.h"
27
28#include "../../events/SDL_mouse_c.h"
29
30#if 0
31#define DEBUG_COCOAMOUSE
32#endif
33
34#ifdef DEBUG_COCOAMOUSE
35#define DLog(fmt, ...) printf("%s: " fmt "\n", __func__, ##__VA_ARGS__)
36#else
37#define DLog(...) \
38 do { \
39 } while (0)
40#endif
41
42@implementation NSCursor (InvisibleCursor)
43+ (NSCursor *)invisibleCursor
44{
45 static NSCursor *invisibleCursor = NULL;
46 if (!invisibleCursor) {
47 // RAW 16x16 transparent GIF
48 static unsigned char cursorBytes[] = {
49 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x10, 0x00, 0x10, 0x00, 0x80,
50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xF9, 0x04,
51 0x01, 0x00, 0x00, 0x01, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x10,
52 0x00, 0x10, 0x00, 0x00, 0x02, 0x0E, 0x8C, 0x8F, 0xA9, 0xCB, 0xED,
53 0x0F, 0xA3, 0x9C, 0xB4, 0xDA, 0x8B, 0xB3, 0x3E, 0x05, 0x00, 0x3B
54 };
55
56 NSData *cursorData = [NSData dataWithBytesNoCopy:&cursorBytes[0]
57 length:sizeof(cursorBytes)
58 freeWhenDone:NO];
59 NSImage *cursorImage = [[NSImage alloc] initWithData:cursorData];
60 invisibleCursor = [[NSCursor alloc] initWithImage:cursorImage
61 hotSpot:NSZeroPoint];
62 }
63
64 return invisibleCursor;
65}
66@end
67
68static SDL_Cursor *Cocoa_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
69{
70 @autoreleasepool {
71 NSImage *nsimage;
72 NSCursor *nscursor = NULL;
73 SDL_Cursor *cursor = NULL;
74
75 nsimage = Cocoa_CreateImage(surface);
76 if (nsimage) {
77 nscursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSMakePoint(hot_x, hot_y)];
78 }
79
80 if (nscursor) {
81 cursor = SDL_calloc(1, sizeof(*cursor));
82 if (cursor) {
83 cursor->internal = (void *)CFBridgingRetain(nscursor);
84 }
85 }
86
87 return cursor;
88 }
89}
90
91/* there are .pdf files of some of the cursors we need, installed by default on macOS, but not available through NSCursor.
92 If we can load them ourselves, use them, otherwise fallback to something standard but not super-great.
93 Since these are under /System, they should be available even to sandboxed apps. */
94static NSCursor *LoadHiddenSystemCursor(NSString *cursorName, SEL fallback)
95{
96 NSString *cursorPath = [@"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/Resources/cursors" stringByAppendingPathComponent:cursorName];
97 NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[cursorPath stringByAppendingPathComponent:@"info.plist"]];
98 // we can't do animation atm. :/
99 const int frames = (int)[[info valueForKey:@"frames"] integerValue];
100 NSCursor *cursor;
101 NSImage *image = [[NSImage alloc] initWithContentsOfFile:[cursorPath stringByAppendingPathComponent:@"cursor.pdf"]];
102 if ((image == nil) || (image.isValid == NO)) {
103 return [NSCursor performSelector:fallback];
104 }
105
106 if (frames > 1) {
107#ifdef MAC_OS_VERSION_12_0 // same value as deprecated symbol.
108 const NSCompositingOperation operation = NSCompositingOperationCopy;
109#else
110 const NSCompositingOperation operation = NSCompositeCopy;
111#endif
112 const NSSize cropped_size = NSMakeSize(image.size.width, (int)(image.size.height / frames));
113 NSImage *cropped = [[NSImage alloc] initWithSize:cropped_size];
114 if (cropped == nil) {
115 return [NSCursor performSelector:fallback];
116 }
117
118 [cropped lockFocus];
119 {
120 const NSRect cropped_rect = NSMakeRect(0, 0, cropped_size.width, cropped_size.height);
121 [image drawInRect:cropped_rect fromRect:cropped_rect operation:operation fraction:1];
122 }
123 [cropped unlockFocus];
124 image = cropped;
125 }
126
127 cursor = [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint([[info valueForKey:@"hotx"] doubleValue], [[info valueForKey:@"hoty"] doubleValue])];
128 return cursor;
129}
130
131static SDL_Cursor *Cocoa_CreateSystemCursor(SDL_SystemCursor id)
132{
133 @autoreleasepool {
134 NSCursor *nscursor = NULL;
135 SDL_Cursor *cursor = NULL;
136
137 switch (id) {
138 case SDL_SYSTEM_CURSOR_DEFAULT:
139 nscursor = [NSCursor arrowCursor];
140 break;
141 case SDL_SYSTEM_CURSOR_TEXT:
142 nscursor = [NSCursor IBeamCursor];
143 break;
144 case SDL_SYSTEM_CURSOR_CROSSHAIR:
145 nscursor = [NSCursor crosshairCursor];
146 break;
147 case SDL_SYSTEM_CURSOR_WAIT: // !!! FIXME: this is more like WAITARROW
148 nscursor = LoadHiddenSystemCursor(@"busybutclickable", @selector(arrowCursor));
149 break;
150 case SDL_SYSTEM_CURSOR_PROGRESS: // !!! FIXME: this is meant to be animated
151 nscursor = LoadHiddenSystemCursor(@"busybutclickable", @selector(arrowCursor));
152 break;
153 case SDL_SYSTEM_CURSOR_NWSE_RESIZE:
154 nscursor = LoadHiddenSystemCursor(@"resizenorthwestsoutheast", @selector(closedHandCursor));
155 break;
156 case SDL_SYSTEM_CURSOR_NESW_RESIZE:
157 nscursor = LoadHiddenSystemCursor(@"resizenortheastsouthwest", @selector(closedHandCursor));
158 break;
159 case SDL_SYSTEM_CURSOR_EW_RESIZE:
160 nscursor = LoadHiddenSystemCursor(@"resizeeastwest", @selector(resizeLeftRightCursor));
161 break;
162 case SDL_SYSTEM_CURSOR_NS_RESIZE:
163 nscursor = LoadHiddenSystemCursor(@"resizenorthsouth", @selector(resizeUpDownCursor));
164 break;
165 case SDL_SYSTEM_CURSOR_MOVE:
166 nscursor = LoadHiddenSystemCursor(@"move", @selector(closedHandCursor));
167 break;
168 case SDL_SYSTEM_CURSOR_NOT_ALLOWED:
169 nscursor = [NSCursor operationNotAllowedCursor];
170 break;
171 case SDL_SYSTEM_CURSOR_POINTER:
172 nscursor = [NSCursor pointingHandCursor];
173 break;
174 case SDL_SYSTEM_CURSOR_NW_RESIZE:
175 nscursor = LoadHiddenSystemCursor(@"resizenorthwestsoutheast", @selector(closedHandCursor));
176 break;
177 case SDL_SYSTEM_CURSOR_N_RESIZE:
178 nscursor = LoadHiddenSystemCursor(@"resizenorthsouth", @selector(resizeUpDownCursor));
179 break;
180 case SDL_SYSTEM_CURSOR_NE_RESIZE:
181 nscursor = LoadHiddenSystemCursor(@"resizenortheastsouthwest", @selector(closedHandCursor));
182 break;
183 case SDL_SYSTEM_CURSOR_E_RESIZE:
184 nscursor = LoadHiddenSystemCursor(@"resizeeastwest", @selector(resizeLeftRightCursor));
185 break;
186 case SDL_SYSTEM_CURSOR_SE_RESIZE:
187 nscursor = LoadHiddenSystemCursor(@"resizenorthwestsoutheast", @selector(closedHandCursor));
188 break;
189 case SDL_SYSTEM_CURSOR_S_RESIZE:
190 nscursor = LoadHiddenSystemCursor(@"resizenorthsouth", @selector(resizeUpDownCursor));
191 break;
192 case SDL_SYSTEM_CURSOR_SW_RESIZE:
193 nscursor = LoadHiddenSystemCursor(@"resizenortheastsouthwest", @selector(closedHandCursor));
194 break;
195 case SDL_SYSTEM_CURSOR_W_RESIZE:
196 nscursor = LoadHiddenSystemCursor(@"resizeeastwest", @selector(resizeLeftRightCursor));
197 break;
198 default:
199 SDL_assert(!"Unknown system cursor");
200 return NULL;
201 }
202
203 if (nscursor) {
204 cursor = SDL_calloc(1, sizeof(*cursor));
205 if (cursor) {
206 // We'll free it later, so retain it here
207 cursor->internal = (void *)CFBridgingRetain(nscursor);
208 }
209 }
210
211 return cursor;
212 }
213}
214
215static SDL_Cursor *Cocoa_CreateDefaultCursor(void)
216{
217 SDL_SystemCursor id = SDL_GetDefaultSystemCursor();
218 return Cocoa_CreateSystemCursor(id);
219}
220
221static void Cocoa_FreeCursor(SDL_Cursor *cursor)
222{
223 @autoreleasepool {
224 CFBridgingRelease((void *)cursor->internal);
225 SDL_free(cursor);
226 }
227}
228
229static bool Cocoa_ShowCursor(SDL_Cursor *cursor)
230{
231 @autoreleasepool {
232 SDL_VideoDevice *device = SDL_GetVideoDevice();
233 SDL_Window *window = (device ? device->windows : NULL);
234 for (; window != NULL; window = window->next) {
235 SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal;
236 if (data) {
237 [data.nswindow performSelectorOnMainThread:@selector(invalidateCursorRectsForView:)
238 withObject:[data.nswindow contentView]
239 waitUntilDone:NO];
240 }
241 }
242 return true;
243 }
244}
245
246static SDL_Window *SDL_FindWindowAtPoint(const float x, const float y)
247{
248 const SDL_FPoint pt = { x, y };
249 SDL_Window *i;
250 for (i = SDL_GetVideoDevice()->windows; i; i = i->next) {
251 const SDL_FRect r = { (float)i->x, (float)i->y, (float)i->w, (float)i->h };
252 if (SDL_PointInRectFloat(&pt, &r)) {
253 return i;
254 }
255 }
256
257 return NULL;
258}
259
260static bool Cocoa_WarpMouseGlobal(float x, float y)
261{
262 CGPoint point;
263 SDL_Mouse *mouse = SDL_GetMouse();
264 if (mouse->focus) {
265 SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)mouse->focus->internal;
266 if ([data.listener isMovingOrFocusClickPending]) {
267 DLog("Postponing warp, window being moved or focused.");
268 [data.listener setPendingMoveX:x Y:y];
269 return true;
270 }
271 }
272 point = CGPointMake(x, y);
273
274 Cocoa_HandleMouseWarp(point.x, point.y);
275
276 CGWarpMouseCursorPosition(point);
277
278 /* CGWarpMouse causes a short delay by default, which is preventable by
279 * Calling this directly after. CGSetLocalEventsSuppressionInterval can also
280 * prevent it, but it's deprecated as macOS 10.6.
281 */
282 if (!mouse->relative_mode) {
283 CGAssociateMouseAndMouseCursorPosition(YES);
284 }
285
286 /* CGWarpMouseCursorPosition doesn't generate a window event, unlike our
287 * other implementations' APIs. Send what's appropriate.
288 */
289 if (!mouse->relative_mode) {
290 SDL_Window *win = SDL_FindWindowAtPoint(x, y);
291 SDL_SetMouseFocus(win);
292 if (win) {
293 SDL_assert(win == mouse->focus);
294 SDL_SendMouseMotion(0, win, SDL_GLOBAL_MOUSE_ID, false, x - win->x, y - win->y);
295 }
296 }
297
298 return true;
299}
300
301static bool Cocoa_WarpMouse(SDL_Window *window, float x, float y)
302{
303 return Cocoa_WarpMouseGlobal(window->x + x, window->y + y);
304}
305
306static bool Cocoa_SetRelativeMouseMode(bool enabled)
307{
308 CGError result;
309
310 if (enabled) {
311 SDL_Window *window = SDL_GetKeyboardFocus();
312 if (window) {
313 /* We will re-apply the relative mode when the window finishes being moved,
314 * if it is being moved right now.
315 */
316 SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal;
317 if ([data.listener isMovingOrFocusClickPending]) {
318 return true;
319 }
320
321 // make sure the mouse isn't at the corner of the window, as this can confuse things if macOS thinks a window resize is happening on the first click.
322 const CGPoint point = CGPointMake((float)(window->x + (window->w / 2)), (float)(window->y + (window->h / 2)));
323 Cocoa_HandleMouseWarp(point.x, point.y);
324 CGWarpMouseCursorPosition(point);
325 }
326 DLog("Turning on.");
327 result = CGAssociateMouseAndMouseCursorPosition(NO);
328 } else {
329 DLog("Turning off.");
330 result = CGAssociateMouseAndMouseCursorPosition(YES);
331 }
332 if (result != kCGErrorSuccess) {
333 return SDL_SetError("CGAssociateMouseAndMouseCursorPosition() failed");
334 }
335
336 /* The hide/unhide calls are redundant most of the time, but they fix
337 * https://bugzilla.libsdl.org/show_bug.cgi?id=2550
338 */
339 if (enabled) {
340 [NSCursor hide];
341 } else {
342 [NSCursor unhide];
343 }
344 return true;
345}
346
347static bool Cocoa_CaptureMouse(SDL_Window *window)
348{
349 /* our Cocoa event code already tracks the mouse outside the window,
350 so all we have to do here is say "okay" and do what we always do. */
351 return true;
352}
353
354static SDL_MouseButtonFlags Cocoa_GetGlobalMouseState(float *x, float *y)
355{
356 const NSUInteger cocoaButtons = [NSEvent pressedMouseButtons];
357 const NSPoint cocoaLocation = [NSEvent mouseLocation];
358 SDL_MouseButtonFlags result = 0;
359
360 *x = cocoaLocation.x;
361 *y = (CGDisplayPixelsHigh(kCGDirectMainDisplay) - cocoaLocation.y);
362
363 result |= (cocoaButtons & (1 << 0)) ? SDL_BUTTON_LMASK : 0;
364 result |= (cocoaButtons & (1 << 1)) ? SDL_BUTTON_RMASK : 0;
365 result |= (cocoaButtons & (1 << 2)) ? SDL_BUTTON_MMASK : 0;
366 result |= (cocoaButtons & (1 << 3)) ? SDL_BUTTON_X1MASK : 0;
367 result |= (cocoaButtons & (1 << 4)) ? SDL_BUTTON_X2MASK : 0;
368
369 return result;
370}
371
372bool Cocoa_InitMouse(SDL_VideoDevice *_this)
373{
374 NSPoint location;
375 SDL_Mouse *mouse = SDL_GetMouse();
376 SDL_MouseData *internal = (SDL_MouseData *)SDL_calloc(1, sizeof(SDL_MouseData));
377 if (internal == NULL) {
378 return false;
379 }
380
381 mouse->internal = internal;
382 mouse->CreateCursor = Cocoa_CreateCursor;
383 mouse->CreateSystemCursor = Cocoa_CreateSystemCursor;
384 mouse->ShowCursor = Cocoa_ShowCursor;
385 mouse->FreeCursor = Cocoa_FreeCursor;
386 mouse->WarpMouse = Cocoa_WarpMouse;
387 mouse->WarpMouseGlobal = Cocoa_WarpMouseGlobal;
388 mouse->SetRelativeMouseMode = Cocoa_SetRelativeMouseMode;
389 mouse->CaptureMouse = Cocoa_CaptureMouse;
390 mouse->GetGlobalMouseState = Cocoa_GetGlobalMouseState;
391
392 SDL_SetDefaultCursor(Cocoa_CreateDefaultCursor());
393
394 location = [NSEvent mouseLocation];
395 internal->lastMoveX = location.x;
396 internal->lastMoveY = location.y;
397 return true;
398}
399
400static void Cocoa_HandleTitleButtonEvent(SDL_VideoDevice *_this, NSEvent *event)
401{
402 SDL_Window *window;
403 NSWindow *nswindow = [event window];
404
405 /* You might land in this function before SDL_Init if showing a message box.
406 Don't dereference a NULL pointer if that happens. */
407 if (_this == NULL) {
408 return;
409 }
410
411 for (window = _this->windows; window; window = window->next) {
412 SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal;
413 if (data && data.nswindow == nswindow) {
414 switch ([event type]) {
415 case NSEventTypeLeftMouseDown:
416 case NSEventTypeRightMouseDown:
417 case NSEventTypeOtherMouseDown:
418 [data.listener setFocusClickPending:[event buttonNumber]];
419 break;
420 case NSEventTypeLeftMouseUp:
421 case NSEventTypeRightMouseUp:
422 case NSEventTypeOtherMouseUp:
423 [data.listener clearFocusClickPending:[event buttonNumber]];
424 break;
425 default:
426 break;
427 }
428 break;
429 }
430 }
431}
432
433static NSWindow *Cocoa_MouseFocus;
434
435NSWindow *Cocoa_GetMouseFocus()
436{
437 return Cocoa_MouseFocus;
438}
439
440void Cocoa_HandleMouseEvent(SDL_VideoDevice *_this, NSEvent *event)
441{
442 SDL_MouseID mouseID = SDL_DEFAULT_MOUSE_ID;
443 SDL_Mouse *mouse;
444 SDL_MouseData *data;
445 NSPoint location;
446 CGFloat lastMoveX, lastMoveY;
447 float deltaX, deltaY;
448 bool seenWarp;
449
450 // All events except NSEventTypeMouseExited can only happen if the window
451 // has mouse focus, so we'll always set the focus even if we happen to miss
452 // NSEventTypeMouseEntered, which apparently happens if the window is
453 // created under the mouse on macOS 12.7
454 NSEventType event_type = [event type];
455 if (event_type == NSEventTypeMouseExited) {
456 Cocoa_MouseFocus = NULL;
457 } else {
458 Cocoa_MouseFocus = [event window];
459 }
460
461 switch (event_type) {
462 case NSEventTypeMouseEntered:
463 case NSEventTypeMouseExited:
464 // Focus is handled above
465 return;
466
467 case NSEventTypeMouseMoved:
468 case NSEventTypeLeftMouseDragged:
469 case NSEventTypeRightMouseDragged:
470 case NSEventTypeOtherMouseDragged:
471 break;
472
473 case NSEventTypeLeftMouseDown:
474 case NSEventTypeLeftMouseUp:
475 case NSEventTypeRightMouseDown:
476 case NSEventTypeRightMouseUp:
477 case NSEventTypeOtherMouseDown:
478 case NSEventTypeOtherMouseUp:
479 if ([event window]) {
480 NSRect windowRect = [[[event window] contentView] frame];
481 if (!NSMouseInRect([event locationInWindow], windowRect, NO)) {
482 Cocoa_HandleTitleButtonEvent(_this, event);
483 return;
484 }
485 }
486 return;
487
488 default:
489 // Ignore any other events.
490 return;
491 }
492
493 mouse = SDL_GetMouse();
494 data = (SDL_MouseData *)mouse->internal;
495 if (!data) {
496 return; // can happen when returning from fullscreen Space on shutdown
497 }
498
499 seenWarp = data->seenWarp;
500 data->seenWarp = NO;
501
502 location = [NSEvent mouseLocation];
503 lastMoveX = data->lastMoveX;
504 lastMoveY = data->lastMoveY;
505 data->lastMoveX = location.x;
506 data->lastMoveY = location.y;
507 DLog("Last seen mouse: (%g, %g)", location.x, location.y);
508
509 // Non-relative movement is handled in -[SDL3Cocoa_WindowListener mouseMoved:]
510 if (!mouse->relative_mode) {
511 return;
512 }
513
514 // Ignore events that aren't inside the client area (i.e. title bar.)
515 if ([event window]) {
516 NSRect windowRect = [[[event window] contentView] frame];
517 if (!NSMouseInRect([event locationInWindow], windowRect, NO)) {
518 return;
519 }
520 }
521
522 deltaX = [event deltaX];
523 deltaY = [event deltaY];
524
525 if (seenWarp) {
526 deltaX += (lastMoveX - data->lastWarpX);
527 deltaY += ((CGDisplayPixelsHigh(kCGDirectMainDisplay) - lastMoveY) - data->lastWarpY);
528
529 DLog("Motion was (%g, %g), offset to (%g, %g)", [event deltaX], [event deltaY], deltaX, deltaY);
530 }
531
532 SDL_SendMouseMotion(Cocoa_GetEventTimestamp([event timestamp]), mouse->focus, mouseID, true, deltaX, deltaY);
533}
534
535void Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event)
536{
537 SDL_MouseID mouseID = SDL_DEFAULT_MOUSE_ID;
538 SDL_MouseWheelDirection direction;
539 CGFloat x, y;
540
541 x = -[event deltaX];
542 y = [event deltaY];
543 direction = SDL_MOUSEWHEEL_NORMAL;
544
545 if ([event isDirectionInvertedFromDevice] == YES) {
546 direction = SDL_MOUSEWHEEL_FLIPPED;
547 }
548
549 /* For discrete scroll events from conventional mice, always send a full tick.
550 For continuous scroll events from trackpads, send fractional deltas for smoother scrolling. */
551 if (![event hasPreciseScrollingDeltas]) {
552 if (x > 0) {
553 x = SDL_ceil(x);
554 } else if (x < 0) {
555 x = SDL_floor(x);
556 }
557 if (y > 0) {
558 y = SDL_ceil(y);
559 } else if (y < 0) {
560 y = SDL_floor(y);
561 }
562 }
563
564 SDL_SendMouseWheel(Cocoa_GetEventTimestamp([event timestamp]), window, mouseID, x, y, direction);
565}
566
567void Cocoa_HandleMouseWarp(CGFloat x, CGFloat y)
568{
569 /* This makes Cocoa_HandleMouseEvent ignore the delta caused by the warp,
570 * since it gets included in the next movement event.
571 */
572 SDL_MouseData *data = (SDL_MouseData *)SDL_GetMouse()->internal;
573 data->lastWarpX = x;
574 data->lastWarpY = y;
575 data->seenWarp = true;
576
577 DLog("(%g, %g)", x, y);
578}
579
580void Cocoa_QuitMouse(SDL_VideoDevice *_this)
581{
582 SDL_Mouse *mouse = SDL_GetMouse();
583 if (mouse) {
584 if (mouse->internal) {
585 SDL_free(mouse->internal);
586 mouse->internal = NULL;
587 }
588 }
589}
590
591#endif // SDL_VIDEO_DRIVER_COCOA