SDL  2.0
SDL_cocoawindow.m
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 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 #if SDL_VIDEO_DRIVER_COCOA
24 
25 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
26 # error SDL for Mac OS X must be built with a 10.7 SDK or above.
27 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1070 */
28 
29 #include "SDL_syswm.h"
30 #include "SDL_timer.h" /* For SDL_GetTicks() */
31 #include "SDL_hints.h"
32 #include "../SDL_sysvideo.h"
33 #include "../../events/SDL_keyboard_c.h"
34 #include "../../events/SDL_mouse_c.h"
35 #include "../../events/SDL_touch_c.h"
36 #include "../../events/SDL_windowevents_c.h"
37 #include "../../events/SDL_dropevents_c.h"
38 #include "SDL_cocoavideo.h"
39 #include "SDL_cocoashape.h"
40 #include "SDL_cocoamouse.h"
41 #include "SDL_cocoaopengl.h"
42 #include "SDL_assert.h"
43 
44 /* #define DEBUG_COCOAWINDOW */
45 
46 #ifdef DEBUG_COCOAWINDOW
47 #define DLog(fmt, ...) printf("%s: " fmt "\n", __func__, ##__VA_ARGS__)
48 #else
49 #define DLog(...) do { } while (0)
50 #endif
51 
52 
53 #define FULLSCREEN_MASK (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN)
54 
55 
56 @interface SDLWindow : NSWindow <NSDraggingDestination>
57 /* These are needed for borderless/fullscreen windows */
58 - (BOOL)canBecomeKeyWindow;
59 - (BOOL)canBecomeMainWindow;
60 - (void)sendEvent:(NSEvent *)event;
61 - (void)doCommandBySelector:(SEL)aSelector;
62 
63 /* Handle drag-and-drop of files onto the SDL window. */
64 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
65 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender;
66 - (BOOL)wantsPeriodicDraggingUpdates;
67 @end
68 
69 @implementation SDLWindow
70 
71 - (BOOL)canBecomeKeyWindow
72 {
73  return YES;
74 }
75 
76 - (BOOL)canBecomeMainWindow
77 {
78  return YES;
79 }
80 
81 - (void)sendEvent:(NSEvent *)event
82 {
83  [super sendEvent:event];
84 
85  if ([event type] != NSLeftMouseUp) {
86  return;
87  }
88 
89  id delegate = [self delegate];
90  if (![delegate isKindOfClass:[Cocoa_WindowListener class]]) {
91  return;
92  }
93 
94  if ([delegate isMoving]) {
95  [delegate windowDidFinishMoving];
96  }
97 }
98 
99 /* We'll respond to selectors by doing nothing so we don't beep.
100  * The escape key gets converted to a "cancel" selector, etc.
101  */
102 - (void)doCommandBySelector:(SEL)aSelector
103 {
104  /*NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector));*/
105 }
106 
107 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
108 {
109  if (([sender draggingSourceOperationMask] & NSDragOperationGeneric) == NSDragOperationGeneric) {
110  return NSDragOperationGeneric;
111  }
112 
113  return NSDragOperationNone; /* no idea what to do with this, reject it. */
114 }
115 
116 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
117 { @autoreleasepool
118 {
119  NSPasteboard *pasteboard = [sender draggingPasteboard];
120  NSArray *types = [NSArray arrayWithObject:NSFilenamesPboardType];
121  NSString *desiredType = [pasteboard availableTypeFromArray:types];
122  if (desiredType == nil) {
123  return NO; /* can't accept anything that's being dropped here. */
124  }
125 
126  NSData *data = [pasteboard dataForType:desiredType];
127  if (data == nil) {
128  return NO;
129  }
130 
131  SDL_assert([desiredType isEqualToString:NSFilenamesPboardType]);
132  NSArray *array = [pasteboard propertyListForType:@"NSFilenamesPboardType"];
133 
134  for (NSString *path in array) {
135  NSURL *fileURL = [[NSURL fileURLWithPath:path] autorelease];
136  NSNumber *isAlias = nil;
137 
138  /* Functionality for resolving URL aliases was added with OS X 10.6. */
139  if ([fileURL respondsToSelector:@selector(getResourceValue:forKey:error:)]) {
140  [fileURL getResourceValue:&isAlias forKey:NSURLIsAliasFileKey error:nil];
141  }
142 
143  /* If the URL is an alias, resolve it. */
144  if ([isAlias boolValue]) {
145  NSURLBookmarkResolutionOptions opts = NSURLBookmarkResolutionWithoutMounting | NSURLBookmarkResolutionWithoutUI;
146  NSData *bookmark = [NSURL bookmarkDataWithContentsOfURL:fileURL error:nil];
147  if (bookmark != nil) {
148  NSURL *resolvedURL = [NSURL URLByResolvingBookmarkData:bookmark
149  options:opts
150  relativeToURL:nil
151  bookmarkDataIsStale:nil
152  error:nil];
153 
154  if (resolvedURL != nil) {
155  fileURL = resolvedURL;
156  }
157  }
158  }
159 
160  if (!SDL_SendDropFile([[fileURL path] UTF8String])) {
161  return NO;
162  }
163  }
164 
165  return YES;
166 }}
167 
168 - (BOOL)wantsPeriodicDraggingUpdates
169 {
170  return NO;
171 }
172 
173 @end
174 
175 
176 static Uint32 s_moveHack;
177 
178 static void ConvertNSRect(NSScreen *screen, BOOL fullscreen, NSRect *r)
179 {
180  r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - r->origin.y - r->size.height;
181 }
182 
183 static void
184 ScheduleContextUpdates(SDL_WindowData *data)
185 {
186  NSOpenGLContext *currentContext = [NSOpenGLContext currentContext];
187  NSMutableArray *contexts = data->nscontexts;
188  @synchronized (contexts) {
189  for (SDLOpenGLContext *context in contexts) {
190  if (context == currentContext) {
191  [context update];
192  } else {
193  [context scheduleUpdate];
194  }
195  }
196  }
197 }
198 
199 static int
200 GetHintCtrlClickEmulateRightClick()
201 {
203  return hint != NULL && *hint != '0';
204 }
205 
206 static unsigned int
207 GetWindowStyle(SDL_Window * window)
208 {
209  unsigned int style;
210 
211  if (window->flags & SDL_WINDOW_FULLSCREEN) {
212  style = NSBorderlessWindowMask;
213  } else {
214  if (window->flags & SDL_WINDOW_BORDERLESS) {
215  style = NSBorderlessWindowMask;
216  } else {
217  style = (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask);
218  }
219  if (window->flags & SDL_WINDOW_RESIZABLE) {
220  style |= NSResizableWindowMask;
221  }
222  }
223  return style;
224 }
225 
226 static SDL_bool
227 SetWindowStyle(SDL_Window * window, unsigned int style)
228 {
229  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
230  NSWindow *nswindow = data->nswindow;
231 
232  if (![nswindow respondsToSelector: @selector(setStyleMask:)]) {
233  return SDL_FALSE;
234  }
235 
236  /* The view responder chain gets messed with during setStyleMask */
237  if ([[nswindow contentView] nextResponder] == data->listener) {
238  [[nswindow contentView] setNextResponder:nil];
239  }
240 
241  [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)style];
242 
243  /* The view responder chain gets messed with during setStyleMask */
244  if ([[nswindow contentView] nextResponder] != data->listener) {
245  [[nswindow contentView] setNextResponder:data->listener];
246  }
247 
248  return SDL_TRUE;
249 }
250 
251 
252 @implementation Cocoa_WindowListener
253 
254 - (void)listen:(SDL_WindowData *)data
255 {
256  NSNotificationCenter *center;
257  NSWindow *window = data->nswindow;
258  NSView *view = [window contentView];
259 
260  _data = data;
261  observingVisible = YES;
262  wasCtrlLeft = NO;
263  wasVisible = [window isVisible];
264  isFullscreenSpace = NO;
267  isMoving = NO;
268  isDragAreaRunning = NO;
269 
270  center = [NSNotificationCenter defaultCenter];
271 
272  if ([window delegate] != nil) {
273  [center addObserver:self selector:@selector(windowDidExpose:) name:NSWindowDidExposeNotification object:window];
274  [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:window];
275  [center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:window];
276  [center addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:window];
277  [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:window];
278  [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:window];
279  [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window];
280  [center addObserver:self selector:@selector(windowDidChangeBackingProperties:) name:NSWindowDidChangeBackingPropertiesNotification object:window];
281  [center addObserver:self selector:@selector(windowWillEnterFullScreen:) name:NSWindowWillEnterFullScreenNotification object:window];
282  [center addObserver:self selector:@selector(windowDidEnterFullScreen:) name:NSWindowDidEnterFullScreenNotification object:window];
283  [center addObserver:self selector:@selector(windowWillExitFullScreen:) name:NSWindowWillExitFullScreenNotification object:window];
284  [center addObserver:self selector:@selector(windowDidExitFullScreen:) name:NSWindowDidExitFullScreenNotification object:window];
285  [center addObserver:self selector:@selector(windowDidFailToEnterFullScreen:) name:@"NSWindowDidFailToEnterFullScreenNotification" object:window];
286  [center addObserver:self selector:@selector(windowDidFailToExitFullScreen:) name:@"NSWindowDidFailToExitFullScreenNotification" object:window];
287  } else {
288  [window setDelegate:self];
289  }
290 
291  /* Haven't found a delegate / notification that triggers when the window is
292  * ordered out (is not visible any more). You can be ordered out without
293  * minimizing, so DidMiniaturize doesn't work. (e.g. -[NSWindow orderOut:])
294  */
295  [window addObserver:self
296  forKeyPath:@"visible"
297  options:NSKeyValueObservingOptionNew
298  context:NULL];
299 
300  [window setNextResponder:self];
301  [window setAcceptsMouseMovedEvents:YES];
302 
303  [view setNextResponder:self];
304 
305  if ([view respondsToSelector:@selector(setAcceptsTouchEvents:)]) {
306  [view setAcceptsTouchEvents:YES];
307  }
308 }
309 
310 - (void)observeValueForKeyPath:(NSString *)keyPath
311  ofObject:(id)object
312  change:(NSDictionary *)change
313  context:(void *)context
314 {
315  if (!observingVisible) {
316  return;
317  }
318 
319  if (object == _data->nswindow && [keyPath isEqualToString:@"visible"]) {
320  int newVisibility = [[change objectForKey:@"new"] intValue];
321  if (newVisibility) {
323  } else {
325  }
326  }
327 }
328 
330 {
331  observingVisible = NO;
332  wasVisible = [_data->nswindow isVisible];
333 }
334 
336 {
337  BOOL isVisible = [_data->nswindow isVisible];
338  observingVisible = YES;
339  if (wasVisible != isVisible) {
340  if (isVisible) {
342  } else {
344  }
345 
346  wasVisible = isVisible;
347  }
348 }
349 
350 -(BOOL) setFullscreenSpace:(BOOL) state
351 {
352  SDL_Window *window = _data->window;
353  NSWindow *nswindow = _data->nswindow;
354  SDL_VideoData *videodata = ((SDL_WindowData *) window->driverdata)->videodata;
355 
356  if (!videodata->allow_spaces) {
357  return NO; /* Spaces are forcibly disabled. */
358  } else if (state && ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP)) {
359  return NO; /* we only allow you to make a Space on FULLSCREEN_DESKTOP windows. */
361  return NO; /* we only handle leaving the Space on windows that were previously FULLSCREEN_DESKTOP. */
362  } else if (state == isFullscreenSpace) {
363  return YES; /* already there. */
364  }
365 
367  if (state) {
368  [self addPendingWindowOperation:PENDING_OPERATION_ENTER_FULLSCREEN];
369  } else {
370  [self addPendingWindowOperation:PENDING_OPERATION_LEAVE_FULLSCREEN];
371  }
372  return YES;
373  }
375 
376  /* you need to be FullScreenPrimary, or toggleFullScreen doesn't work. Unset it again in windowDidExitFullScreen. */
377  [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
378  [nswindow performSelectorOnMainThread: @selector(toggleFullScreen:) withObject:nswindow waitUntilDone:NO];
379  return YES;
380 }
381 
382 -(BOOL) isInFullscreenSpace
383 {
384  return isFullscreenSpace;
385 }
386 
388 {
389  return inFullscreenTransition;
390 }
391 
392 -(void) addPendingWindowOperation:(PendingWindowOperation) operation
393 {
394  pendingWindowOperation = operation;
395 }
396 
397 - (void)close
398 {
399  NSNotificationCenter *center;
400  NSWindow *window = _data->nswindow;
401  NSView *view = [window contentView];
402 
403  center = [NSNotificationCenter defaultCenter];
404 
405  if ([window delegate] != self) {
406  [center removeObserver:self name:NSWindowDidExposeNotification object:window];
407  [center removeObserver:self name:NSWindowDidMoveNotification object:window];
408  [center removeObserver:self name:NSWindowDidResizeNotification object:window];
409  [center removeObserver:self name:NSWindowDidMiniaturizeNotification object:window];
410  [center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window];
411  [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:window];
412  [center removeObserver:self name:NSWindowDidResignKeyNotification object:window];
413  [center removeObserver:self name:NSWindowDidChangeBackingPropertiesNotification object:window];
414  [center removeObserver:self name:NSWindowWillEnterFullScreenNotification object:window];
415  [center removeObserver:self name:NSWindowDidEnterFullScreenNotification object:window];
416  [center removeObserver:self name:NSWindowWillExitFullScreenNotification object:window];
417  [center removeObserver:self name:NSWindowDidExitFullScreenNotification object:window];
418  [center removeObserver:self name:@"NSWindowDidFailToEnterFullScreenNotification" object:window];
419  [center removeObserver:self name:@"NSWindowDidFailToExitFullScreenNotification" object:window];
420  } else {
421  [window setDelegate:nil];
422  }
423 
424  [window removeObserver:self forKeyPath:@"visible"];
425 
426  if ([window nextResponder] == self) {
427  [window setNextResponder:nil];
428  }
429  if ([view nextResponder] == self) {
430  [view setNextResponder:nil];
431  }
432 }
433 
434 - (BOOL)isMoving
435 {
436  return isMoving;
437 }
438 
439 -(void) setPendingMoveX:(int)x Y:(int)y
440 {
443 }
444 
446 {
447  if ([self isMoving]) {
448  isMoving = NO;
449 
450  SDL_Mouse *mouse = SDL_GetMouse();
451  if (pendingWindowWarpX != INT_MAX && pendingWindowWarpY != INT_MAX) {
454  }
455  if (mouse->relative_mode && !mouse->relative_mode_warp && mouse->focus == _data->window) {
457  }
458  }
459 }
460 
461 - (BOOL)windowShouldClose:(id)sender
462 {
464  return NO;
465 }
466 
467 - (void)windowDidExpose:(NSNotification *)aNotification
468 {
470 }
471 
472 - (void)windowWillMove:(NSNotification *)aNotification
473 {
474  if ([_data->nswindow isKindOfClass:[SDLWindow class]]) {
476  isMoving = YES;
477  }
478 }
479 
480 - (void)windowDidMove:(NSNotification *)aNotification
481 {
482  int x, y;
483  SDL_Window *window = _data->window;
484  NSWindow *nswindow = _data->nswindow;
485  BOOL fullscreen = window->flags & FULLSCREEN_MASK;
486  NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
487  ConvertNSRect([nswindow screen], fullscreen, &rect);
488 
489  if (s_moveHack) {
490  SDL_bool blockMove = ((SDL_GetTicks() - s_moveHack) < 500);
491 
492  s_moveHack = 0;
493 
494  if (blockMove) {
495  /* Cocoa is adjusting the window in response to a mode change */
496  rect.origin.x = window->x;
497  rect.origin.y = window->y;
498  ConvertNSRect([nswindow screen], fullscreen, &rect);
499  [nswindow setFrameOrigin:rect.origin];
500  return;
501  }
502  }
503 
504  x = (int)rect.origin.x;
505  y = (int)rect.origin.y;
506 
507  ScheduleContextUpdates(_data);
508 
510 }
511 
512 - (void)windowDidResize:(NSNotification *)aNotification
513 {
515  /* We'll take care of this at the end of the transition */
516  return;
517  }
518 
519  SDL_Window *window = _data->window;
520  NSWindow *nswindow = _data->nswindow;
521  int x, y, w, h;
522  NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
523  ConvertNSRect([nswindow screen], (window->flags & FULLSCREEN_MASK), &rect);
524  x = (int)rect.origin.x;
525  y = (int)rect.origin.y;
526  w = (int)rect.size.width;
527  h = (int)rect.size.height;
528 
529  if (SDL_IsShapedWindow(window)) {
530  Cocoa_ResizeWindowShape(window);
531  }
532 
533  ScheduleContextUpdates(_data);
534 
535  /* The window can move during a resize event, such as when maximizing
536  or resizing from a corner */
539 
540  const BOOL zoomed = [nswindow isZoomed];
541  if (!zoomed) {
543  } else if (zoomed) {
545  }
546 }
547 
548 - (void)windowDidMiniaturize:(NSNotification *)aNotification
549 {
551 }
552 
553 - (void)windowDidDeminiaturize:(NSNotification *)aNotification
554 {
556 }
557 
558 - (void)windowDidBecomeKey:(NSNotification *)aNotification
559 {
560  SDL_Window *window = _data->window;
561  SDL_Mouse *mouse = SDL_GetMouse();
562 
563  /* We're going to get keyboard events, since we're key. */
564  /* This needs to be done before restoring the relative mouse mode. */
565  SDL_SetKeyboardFocus(window);
566 
567  if (mouse->relative_mode && !mouse->relative_mode_warp && ![self isMoving]) {
569  }
570 
571  /* If we just gained focus we need the updated mouse position */
572  if (!mouse->relative_mode) {
573  NSPoint point;
574  int x, y;
575 
576  point = [_data->nswindow mouseLocationOutsideOfEventStream];
577  x = (int)point.x;
578  y = (int)(window->h - point.y);
579 
580  if (x >= 0 && x < window->w && y >= 0 && y < window->h) {
581  SDL_SendMouseMotion(window, 0, 0, x, y);
582  }
583  }
584 
585  /* Check to see if someone updated the clipboard */
587 
589  [NSMenu setMenuBarVisible:NO];
590  }
591 
592  /* On pre-10.6, you might have the capslock key state wrong now because we can't check here. */
593  if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_6) {
594  const unsigned int newflags = [NSEvent modifierFlags] & NSAlphaShiftKeyMask;
595  _data->videodata->modifierFlags = (_data->videodata->modifierFlags & ~NSAlphaShiftKeyMask) | newflags;
596  SDL_ToggleModState(KMOD_CAPS, newflags != 0);
597  }
598 }
599 
600 - (void)windowDidResignKey:(NSNotification *)aNotification
601 {
602  SDL_Mouse *mouse = SDL_GetMouse();
603  if (mouse->relative_mode && !mouse->relative_mode_warp) {
605  }
606 
607  /* Some other window will get mouse events, since we're not key. */
608  if (SDL_GetMouseFocus() == _data->window) {
610  }
611 
612  /* Some other window will get keyboard events, since we're not key. */
613  if (SDL_GetKeyboardFocus() == _data->window) {
615  }
616 
617  if (isFullscreenSpace) {
618  [NSMenu setMenuBarVisible:YES];
619  }
620 }
621 
622 - (void)windowDidChangeBackingProperties:(NSNotification *)aNotification
623 {
624  NSNumber *oldscale = [[aNotification userInfo] objectForKey:NSBackingPropertyOldScaleFactorKey];
625 
627  return;
628  }
629 
630  if ([oldscale doubleValue] != [_data->nswindow backingScaleFactor]) {
631  /* Force a resize event when the backing scale factor changes. */
632  _data->window->w = 0;
633  _data->window->h = 0;
634  [self windowDidResize:aNotification];
635  }
636 }
637 
638 - (void)windowWillEnterFullScreen:(NSNotification *)aNotification
639 {
640  SDL_Window *window = _data->window;
641 
642  SetWindowStyle(window, (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask));
643 
644  isFullscreenSpace = YES;
646 }
647 
648 - (void)windowDidFailToEnterFullScreen:(NSNotification *)aNotification
649 {
650  SDL_Window *window = _data->window;
651 
652  if (window->is_destroying) {
653  return;
654  }
655 
656  SetWindowStyle(window, GetWindowStyle(window));
657 
658  isFullscreenSpace = NO;
660 
661  [self windowDidExitFullScreen:nil];
662 }
663 
664 - (void)windowDidEnterFullScreen:(NSNotification *)aNotification
665 {
666  SDL_Window *window = _data->window;
667 
669 
672  [self setFullscreenSpace:NO];
673  } else {
675  [NSMenu setMenuBarVisible:NO];
676  }
677 
679  /* Force the size change event in case it was delivered earlier
680  while the window was still animating into place.
681  */
682  window->w = 0;
683  window->h = 0;
684  [self windowDidResize:aNotification];
685  }
686 }
687 
688 - (void)windowWillExitFullScreen:(NSNotification *)aNotification
689 {
690  SDL_Window *window = _data->window;
691 
692  /* As of OS X 10.11, the window seems to need to be resizable when exiting
693  a Space, in order for it to resize back to its windowed-mode size.
694  */
695  SetWindowStyle(window, GetWindowStyle(window) | NSResizableWindowMask);
696 
697  isFullscreenSpace = NO;
699 }
700 
701 - (void)windowDidFailToExitFullScreen:(NSNotification *)aNotification
702 {
703  SDL_Window *window = _data->window;
704 
705  if (window->is_destroying) {
706  return;
707  }
708 
709  SetWindowStyle(window, (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask));
710 
711  isFullscreenSpace = YES;
713 
714  [self windowDidEnterFullScreen:nil];
715 }
716 
717 - (void)windowDidExitFullScreen:(NSNotification *)aNotification
718 {
719  SDL_Window *window = _data->window;
720  NSWindow *nswindow = _data->nswindow;
721 
723 
724  SetWindowStyle(window, GetWindowStyle(window));
725 
726  [nswindow setLevel:kCGNormalWindowLevel];
727 
730  [self setFullscreenSpace:YES];
733  [nswindow miniaturize:nil];
734  } else {
735  /* Adjust the fullscreen toggle button and readd menu now that we're here. */
736  if (window->flags & SDL_WINDOW_RESIZABLE) {
737  /* resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar. */
738  [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
739  } else {
740  [nswindow setCollectionBehavior:NSWindowCollectionBehaviorManaged];
741  }
742  [NSMenu setMenuBarVisible:YES];
743 
745  /* Force the size change event in case it was delivered earlier
746  while the window was still animating into place.
747  */
748  window->w = 0;
749  window->h = 0;
750  [self windowDidResize:aNotification];
751 
752  /* FIXME: Why does the window get hidden? */
753  if (window->flags & SDL_WINDOW_SHOWN) {
755  }
756  }
757 }
758 
759 -(NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions
760 {
762  return NSApplicationPresentationFullScreen | NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar;
763  } else {
764  return proposedOptions;
765  }
766 }
767 
768 
769 /* We'll respond to key events by doing nothing so we don't beep.
770  * We could handle key messages here, but we lose some in the NSApp dispatch,
771  * where they get converted to action messages, etc.
772  */
773 - (void)flagsChanged:(NSEvent *)theEvent
774 {
775  /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
776 }
777 - (void)keyDown:(NSEvent *)theEvent
778 {
779  /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
780 }
781 - (void)keyUp:(NSEvent *)theEvent
782 {
783  /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
784 }
785 
786 /* We'll respond to selectors by doing nothing so we don't beep.
787  * The escape key gets converted to a "cancel" selector, etc.
788  */
789 - (void)doCommandBySelector:(SEL)aSelector
790 {
791  /*NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector));*/
792 }
793 
794 - (BOOL)processHitTest:(NSEvent *)theEvent
795 {
796  SDL_assert(isDragAreaRunning == [_data->nswindow isMovableByWindowBackground]);
797 
798  if (_data->window->hit_test) { /* if no hit-test, skip this. */
799  const NSPoint location = [theEvent locationInWindow];
800  const SDL_Point point = { (int) location.x, _data->window->h - (((int) location.y)-1) };
802  if (rc == SDL_HITTEST_DRAGGABLE) {
803  if (!isDragAreaRunning) {
804  isDragAreaRunning = YES;
805  [_data->nswindow setMovableByWindowBackground:YES];
806  }
807  return YES; /* dragging! */
808  }
809  }
810 
811  if (isDragAreaRunning) {
812  isDragAreaRunning = NO;
813  [_data->nswindow setMovableByWindowBackground:NO];
814  return YES; /* was dragging, drop event. */
815  }
816 
817  return NO; /* not a special area, carry on. */
818 }
819 
820 - (void)mouseDown:(NSEvent *)theEvent
821 {
822  int button;
823 
824  /* Ignore events that aren't inside the client area (i.e. title bar.) */
825  if ([theEvent window]) {
826  NSRect windowRect = [[[theEvent window] contentView] frame];
827 
828  /* add one to size, since NSPointInRect is exclusive of the bottom
829  edges, which mean it misses the top of the window by one pixel
830  (as the origin is the bottom left). */
831  windowRect.size.width += 1;
832  windowRect.size.height += 1;
833 
834  if (!NSPointInRect([theEvent locationInWindow], windowRect)) {
835  return;
836  }
837  }
838 
839  if ([self processHitTest:theEvent]) {
840  return; /* dragging, drop event. */
841  }
842 
843  switch ([theEvent buttonNumber]) {
844  case 0:
845  if (([theEvent modifierFlags] & NSControlKeyMask) &&
846  GetHintCtrlClickEmulateRightClick()) {
847  wasCtrlLeft = YES;
848  button = SDL_BUTTON_RIGHT;
849  } else {
850  wasCtrlLeft = NO;
851  button = SDL_BUTTON_LEFT;
852  }
853  break;
854  case 1:
855  button = SDL_BUTTON_RIGHT;
856  break;
857  case 2:
858  button = SDL_BUTTON_MIDDLE;
859  break;
860  default:
861  button = [theEvent buttonNumber] + 1;
862  break;
863  }
865 }
866 
867 - (void)rightMouseDown:(NSEvent *)theEvent
868 {
869  [self mouseDown:theEvent];
870 }
871 
872 - (void)otherMouseDown:(NSEvent *)theEvent
873 {
874  [self mouseDown:theEvent];
875 }
876 
877 - (void)mouseUp:(NSEvent *)theEvent
878 {
879  int button;
880 
881  if ([self processHitTest:theEvent]) {
882  return; /* stopped dragging, drop event. */
883  }
884 
885  switch ([theEvent buttonNumber]) {
886  case 0:
887  if (wasCtrlLeft) {
888  button = SDL_BUTTON_RIGHT;
889  wasCtrlLeft = NO;
890  } else {
891  button = SDL_BUTTON_LEFT;
892  }
893  break;
894  case 1:
895  button = SDL_BUTTON_RIGHT;
896  break;
897  case 2:
898  button = SDL_BUTTON_MIDDLE;
899  break;
900  default:
901  button = [theEvent buttonNumber] + 1;
902  break;
903  }
905 }
906 
907 - (void)rightMouseUp:(NSEvent *)theEvent
908 {
909  [self mouseUp:theEvent];
910 }
911 
912 - (void)otherMouseUp:(NSEvent *)theEvent
913 {
914  [self mouseUp:theEvent];
915 }
916 
917 - (void)mouseMoved:(NSEvent *)theEvent
918 {
919  SDL_Mouse *mouse = SDL_GetMouse();
920  SDL_Window *window = _data->window;
921  NSPoint point;
922  int x, y;
923 
924  if ([self processHitTest:theEvent]) {
925  return; /* dragging, drop event. */
926  }
927 
928  if (mouse->relative_mode) {
929  return;
930  }
931 
932  point = [theEvent locationInWindow];
933  x = (int)point.x;
934  y = (int)(window->h - point.y);
935 
936  if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
937  if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
938  if (x < 0) {
939  x = 0;
940  } else if (x >= window->w) {
941  x = window->w - 1;
942  }
943  if (y < 0) {
944  y = 0;
945  } else if (y >= window->h) {
946  y = window->h - 1;
947  }
948 
949 #if !SDL_MAC_NO_SANDBOX
950  CGPoint cgpoint;
951 
952  /* When SDL_MAC_NO_SANDBOX is set, this is handled by
953  * SDL_cocoamousetap.m.
954  */
955 
956  cgpoint.x = window->x + x;
957  cgpoint.y = window->y + y;
958 
959  /* According to the docs, this was deprecated in 10.6, but it's still
960  * around. The substitute requires a CGEventSource, but I'm not entirely
961  * sure how we'd procure the right one for this event.
962  */
963  CGSetLocalEventsSuppressionInterval(0.0);
964  CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
965  CGSetLocalEventsSuppressionInterval(0.25);
966 
967  Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y);
968 #endif
969  }
970  }
971  SDL_SendMouseMotion(window, 0, 0, x, y);
972 }
973 
974 - (void)mouseDragged:(NSEvent *)theEvent
975 {
976  [self mouseMoved:theEvent];
977 }
978 
979 - (void)rightMouseDragged:(NSEvent *)theEvent
980 {
981  [self mouseMoved:theEvent];
982 }
983 
984 - (void)otherMouseDragged:(NSEvent *)theEvent
985 {
986  [self mouseMoved:theEvent];
987 }
988 
989 - (void)scrollWheel:(NSEvent *)theEvent
990 {
991  Cocoa_HandleMouseWheel(_data->window, theEvent);
992 }
993 
994 - (void)touchesBeganWithEvent:(NSEvent *) theEvent
995 {
996  NSSet *touches = [theEvent touchesMatchingPhase:NSTouchPhaseAny inView:nil];
997  int existingTouchCount = 0;
998 
999  for (NSTouch* touch in touches) {
1000  if ([touch phase] != NSTouchPhaseBegan) {
1001  existingTouchCount++;
1002  }
1003  }
1004  if (existingTouchCount == 0) {
1005  SDL_TouchID touchID = (SDL_TouchID)(intptr_t)[[touches anyObject] device];
1006  int numFingers = SDL_GetNumTouchFingers(touchID);
1007  DLog("Reset Lost Fingers: %d", numFingers);
1008  for (--numFingers; numFingers >= 0; --numFingers) {
1009  SDL_Finger* finger = SDL_GetTouchFinger(touchID, numFingers);
1010  SDL_SendTouch(touchID, finger->id, SDL_FALSE, 0, 0, 0);
1011  }
1012  }
1013 
1014  DLog("Began Fingers: %lu .. existing: %d", (unsigned long)[touches count], existingTouchCount);
1015  [self handleTouches:NSTouchPhaseBegan withEvent:theEvent];
1016 }
1017 
1018 - (void)touchesMovedWithEvent:(NSEvent *) theEvent
1019 {
1020  [self handleTouches:NSTouchPhaseMoved withEvent:theEvent];
1021 }
1022 
1023 - (void)touchesEndedWithEvent:(NSEvent *) theEvent
1024 {
1025  [self handleTouches:NSTouchPhaseEnded withEvent:theEvent];
1026 }
1027 
1028 - (void)touchesCancelledWithEvent:(NSEvent *) theEvent
1029 {
1030  [self handleTouches:NSTouchPhaseCancelled withEvent:theEvent];
1031 }
1032 
1033 - (void)handleTouches:(NSTouchPhase) phase withEvent:(NSEvent *) theEvent
1034 {
1035  NSSet *touches = [theEvent touchesMatchingPhase:phase inView:nil];
1036 
1037  for (NSTouch *touch in touches) {
1038  const SDL_TouchID touchId = (SDL_TouchID)(intptr_t)[touch device];
1039  if (SDL_AddTouch(touchId, "") < 0) {
1040  return;
1041  }
1042 
1043  const SDL_FingerID fingerId = (SDL_FingerID)(intptr_t)[touch identity];
1044  float x = [touch normalizedPosition].x;
1045  float y = [touch normalizedPosition].y;
1046  /* Make the origin the upper left instead of the lower left */
1047  y = 1.0f - y;
1048 
1049  switch (phase) {
1050  case NSTouchPhaseBegan:
1051  SDL_SendTouch(touchId, fingerId, SDL_TRUE, x, y, 1.0f);
1052  break;
1053  case NSTouchPhaseEnded:
1054  case NSTouchPhaseCancelled:
1055  SDL_SendTouch(touchId, fingerId, SDL_FALSE, x, y, 1.0f);
1056  break;
1057  case NSTouchPhaseMoved:
1058  SDL_SendTouchMotion(touchId, fingerId, x, y, 1.0f);
1059  break;
1060  default:
1061  break;
1062  }
1063  }
1064 }
1065 
1066 @end
1067 
1068 @interface SDLView : NSView {
1069  SDL_Window *_sdlWindow;
1070 }
1071 
1072 - (void)setSDLWindow:(SDL_Window*)window;
1073 
1074 /* The default implementation doesn't pass rightMouseDown to responder chain */
1075 - (void)rightMouseDown:(NSEvent *)theEvent;
1076 - (BOOL)mouseDownCanMoveWindow;
1077 - (void)drawRect:(NSRect)dirtyRect;
1078 @end
1079 
1080 @implementation SDLView
1081 - (void)setSDLWindow:(SDL_Window*)window
1082 {
1083  _sdlWindow = window;
1084 }
1085 
1086 - (void)drawRect:(NSRect)dirtyRect
1087 {
1088  SDL_SendWindowEvent(_sdlWindow, SDL_WINDOWEVENT_EXPOSED, 0, 0);
1089 }
1090 
1091 - (void)rightMouseDown:(NSEvent *)theEvent
1092 {
1093  [[self nextResponder] rightMouseDown:theEvent];
1094 }
1095 
1096 - (BOOL)mouseDownCanMoveWindow
1097 {
1098  /* Always say YES, but this doesn't do anything until we call
1099  -[NSWindow setMovableByWindowBackground:YES], which we ninja-toggle
1100  during mouse events when we're using a drag area. */
1101  return YES;
1102 }
1103 
1104 - (void)resetCursorRects
1105 {
1106  [super resetCursorRects];
1107  SDL_Mouse *mouse = SDL_GetMouse();
1108 
1109  if (mouse->cursor_shown && mouse->cur_cursor && !mouse->relative_mode) {
1110  [self addCursorRect:[self bounds]
1111  cursor:mouse->cur_cursor->driverdata];
1112  } else {
1113  [self addCursorRect:[self bounds]
1114  cursor:[NSCursor invisibleCursor]];
1115  }
1116 }
1117 @end
1118 
1119 static int
1120 SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created)
1121 { @autoreleasepool
1122 {
1123  SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
1124  SDL_WindowData *data;
1125 
1126  /* Allocate the window data */
1127  window->driverdata = data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
1128  if (!data) {
1129  return SDL_OutOfMemory();
1130  }
1131  data->window = window;
1132  data->nswindow = nswindow;
1133  data->created = created;
1134  data->videodata = videodata;
1135  data->nscontexts = [[NSMutableArray alloc] init];
1136 
1137  /* Create an event listener for the window */
1138  data->listener = [[Cocoa_WindowListener alloc] init];
1139 
1140  /* Fill in the SDL window with the window data */
1141  {
1142  NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
1143  ConvertNSRect([nswindow screen], (window->flags & FULLSCREEN_MASK), &rect);
1144  window->x = (int)rect.origin.x;
1145  window->y = (int)rect.origin.y;
1146  window->w = (int)rect.size.width;
1147  window->h = (int)rect.size.height;
1148  }
1149 
1150  /* Set up the listener after we create the view */
1151  [data->listener listen:data];
1152 
1153  if ([nswindow isVisible]) {
1154  window->flags |= SDL_WINDOW_SHOWN;
1155  } else {
1156  window->flags &= ~SDL_WINDOW_SHOWN;
1157  }
1158 
1159  {
1160  unsigned int style = [nswindow styleMask];
1161 
1162  if (style == NSBorderlessWindowMask) {
1163  window->flags |= SDL_WINDOW_BORDERLESS;
1164  } else {
1165  window->flags &= ~SDL_WINDOW_BORDERLESS;
1166  }
1167  if (style & NSResizableWindowMask) {
1168  window->flags |= SDL_WINDOW_RESIZABLE;
1169  } else {
1170  window->flags &= ~SDL_WINDOW_RESIZABLE;
1171  }
1172  }
1173 
1174  /* isZoomed always returns true if the window is not resizable */
1175  if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
1176  window->flags |= SDL_WINDOW_MAXIMIZED;
1177  } else {
1178  window->flags &= ~SDL_WINDOW_MAXIMIZED;
1179  }
1180 
1181  if ([nswindow isMiniaturized]) {
1182  window->flags |= SDL_WINDOW_MINIMIZED;
1183  } else {
1184  window->flags &= ~SDL_WINDOW_MINIMIZED;
1185  }
1186 
1187  if ([nswindow isKeyWindow]) {
1188  window->flags |= SDL_WINDOW_INPUT_FOCUS;
1190  }
1191 
1192  /* Prevents the window's "window device" from being destroyed when it is
1193  * hidden. See http://www.mikeash.com/pyblog/nsopenglcontext-and-one-shot.html
1194  */
1195  [nswindow setOneShot:NO];
1196 
1197  /* All done! */
1198  window->driverdata = data;
1199  return 0;
1200 }}
1201 
1202 int
1204 { @autoreleasepool
1205 {
1206  SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
1207  NSWindow *nswindow;
1208  SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
1209  NSRect rect;
1210  SDL_Rect bounds;
1211  unsigned int style;
1212  NSArray *screens = [NSScreen screens];
1213 
1214  Cocoa_GetDisplayBounds(_this, display, &bounds);
1215  rect.origin.x = window->x;
1216  rect.origin.y = window->y;
1217  rect.size.width = window->w;
1218  rect.size.height = window->h;
1219  ConvertNSRect([screens objectAtIndex:0], (window->flags & FULLSCREEN_MASK), &rect);
1220 
1221  style = GetWindowStyle(window);
1222 
1223  /* Figure out which screen to place this window */
1224  NSScreen *screen = nil;
1225  for (NSScreen *candidate in screens) {
1226  NSRect screenRect = [candidate frame];
1227  if (rect.origin.x >= screenRect.origin.x &&
1228  rect.origin.x < screenRect.origin.x + screenRect.size.width &&
1229  rect.origin.y >= screenRect.origin.y &&
1230  rect.origin.y < screenRect.origin.y + screenRect.size.height) {
1231  screen = candidate;
1232  rect.origin.x -= screenRect.origin.x;
1233  rect.origin.y -= screenRect.origin.y;
1234  }
1235  }
1236 
1237  @try {
1238  nswindow = [[SDLWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:NO screen:screen];
1239  }
1240  @catch (NSException *e) {
1241  return SDL_SetError("%s", [[e reason] UTF8String]);
1242  }
1243  [nswindow setBackgroundColor:[NSColor blackColor]];
1244 
1245  if (videodata->allow_spaces) {
1246  SDL_assert(floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6);
1247  SDL_assert([nswindow respondsToSelector:@selector(toggleFullScreen:)]);
1248  /* we put FULLSCREEN_DESKTOP windows in their own Space, without a toggle button or menubar, later */
1249  if (window->flags & SDL_WINDOW_RESIZABLE) {
1250  /* resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar. */
1251  [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
1252  }
1253  }
1254 
1255  /* Create a default view for this window */
1256  rect = [nswindow contentRectForFrameRect:[nswindow frame]];
1257  SDLView *contentView = [[SDLView alloc] initWithFrame:rect];
1258  [contentView setSDLWindow:window];
1259 
1260  if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
1261  if ([contentView respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) {
1262  [contentView setWantsBestResolutionOpenGLSurface:YES];
1263  }
1264  }
1265 
1266  [nswindow setContentView: contentView];
1267  [contentView release];
1268 
1269  /* Allow files and folders to be dragged onto the window by users */
1270  [nswindow registerForDraggedTypes:[NSArray arrayWithObject:(NSString *)kUTTypeFileURL]];
1271 
1272  if (SetupWindowData(_this, window, nswindow, SDL_TRUE) < 0) {
1273  [nswindow release];
1274  return -1;
1275  }
1276  return 0;
1277 }}
1278 
1279 int
1280 Cocoa_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
1281 { @autoreleasepool
1282 {
1283  NSWindow *nswindow = (NSWindow *) data;
1284  NSString *title;
1285 
1286  /* Query the title from the existing window */
1287  title = [nswindow title];
1288  if (title) {
1289  window->title = SDL_strdup([title UTF8String]);
1290  }
1291 
1292  return SetupWindowData(_this, window, nswindow, SDL_FALSE);
1293 }}
1294 
1295 void
1297 { @autoreleasepool
1298 {
1299  const char *title = window->title ? window->title : "";
1300  NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
1301  NSString *string = [[NSString alloc] initWithUTF8String:title];
1302  [nswindow setTitle:string];
1303  [string release];
1304 }}
1305 
1306 void
1308 { @autoreleasepool
1309 {
1310  NSImage *nsimage = Cocoa_CreateImage(icon);
1311 
1312  if (nsimage) {
1313  [NSApp setApplicationIconImage:nsimage];
1314  }
1315 }}
1316 
1317 void
1319 { @autoreleasepool
1320 {
1321  SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
1322  NSWindow *nswindow = windata->nswindow;
1323  NSRect rect;
1324  Uint32 moveHack;
1325 
1326  rect.origin.x = window->x;
1327  rect.origin.y = window->y;
1328  rect.size.width = window->w;
1329  rect.size.height = window->h;
1330  ConvertNSRect([nswindow screen], (window->flags & FULLSCREEN_MASK), &rect);
1331 
1332  moveHack = s_moveHack;
1333  s_moveHack = 0;
1334  [nswindow setFrameOrigin:rect.origin];
1335  s_moveHack = moveHack;
1336 
1337  ScheduleContextUpdates(windata);
1338 }}
1339 
1340 void
1342 { @autoreleasepool
1343 {
1344  SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
1345  NSWindow *nswindow = windata->nswindow;
1346  NSRect rect;
1347  Uint32 moveHack;
1348 
1349  /* Cocoa will resize the window from the bottom-left rather than the
1350  * top-left when -[nswindow setContentSize:] is used, so we must set the
1351  * entire frame based on the new size, in order to preserve the position.
1352  */
1353  rect.origin.x = window->x;
1354  rect.origin.y = window->y;
1355  rect.size.width = window->w;
1356  rect.size.height = window->h;
1357  ConvertNSRect([nswindow screen], (window->flags & FULLSCREEN_MASK), &rect);
1358 
1359  moveHack = s_moveHack;
1360  s_moveHack = 0;
1361  [nswindow setFrame:[nswindow frameRectForContentRect:rect] display:YES];
1362  s_moveHack = moveHack;
1363 
1364  ScheduleContextUpdates(windata);
1365 }}
1366 
1367 void
1369 { @autoreleasepool
1370 {
1371  SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
1372 
1373  NSSize minSize;
1374  minSize.width = window->min_w;
1375  minSize.height = window->min_h;
1376 
1377  [windata->nswindow setContentMinSize:minSize];
1378 }}
1379 
1380 void
1382 { @autoreleasepool
1383 {
1384  SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
1385 
1386  NSSize maxSize;
1387  maxSize.width = window->max_w;
1388  maxSize.height = window->max_h;
1389 
1390  [windata->nswindow setContentMaxSize:maxSize];
1391 }}
1392 
1393 void
1395 { @autoreleasepool
1396 {
1397  SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata);
1398  NSWindow *nswindow = windowData->nswindow;
1399 
1400  if (![nswindow isMiniaturized]) {
1401  [windowData->listener pauseVisibleObservation];
1402  [nswindow makeKeyAndOrderFront:nil];
1403  [windowData->listener resumeVisibleObservation];
1404  }
1405 }}
1406 
1407 void
1409 { @autoreleasepool
1410 {
1411  NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
1412 
1413  [nswindow orderOut:nil];
1414 }}
1415 
1416 void
1418 { @autoreleasepool
1419 {
1420  SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata);
1421  NSWindow *nswindow = windowData->nswindow;
1422 
1423  /* makeKeyAndOrderFront: has the side-effect of deminiaturizing and showing
1424  a minimized or hidden window, so check for that before showing it.
1425  */
1426  [windowData->listener pauseVisibleObservation];
1427  if (![nswindow isMiniaturized] && [nswindow isVisible]) {
1428  [NSApp activateIgnoringOtherApps:YES];
1429  [nswindow makeKeyAndOrderFront:nil];
1430  }
1431  [windowData->listener resumeVisibleObservation];
1432 }}
1433 
1434 void
1436 { @autoreleasepool
1437 {
1438  SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
1439  NSWindow *nswindow = windata->nswindow;
1440 
1441  [nswindow zoom:nil];
1442 
1443  ScheduleContextUpdates(windata);
1444 }}
1445 
1446 void
1448 { @autoreleasepool
1449 {
1450  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1451  NSWindow *nswindow = data->nswindow;
1452 
1453  if ([data->listener isInFullscreenSpaceTransition]) {
1454  [data->listener addPendingWindowOperation:PENDING_OPERATION_MINIMIZE];
1455  } else {
1456  [nswindow miniaturize:nil];
1457  }
1458 }}
1459 
1460 void
1462 { @autoreleasepool
1463 {
1464  NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
1465 
1466  if ([nswindow isMiniaturized]) {
1467  [nswindow deminiaturize:nil];
1468  } else if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
1469  [nswindow zoom:nil];
1470  }
1471 }}
1472 
1473 static NSWindow *
1474 Cocoa_RebuildWindow(SDL_WindowData * data, NSWindow * nswindow, unsigned style)
1475 {
1476  if (!data->created) {
1477  /* Don't mess with other people's windows... */
1478  return nswindow;
1479  }
1480 
1481  [data->listener close];
1482  data->nswindow = [[SDLWindow alloc] initWithContentRect:[[nswindow contentView] frame] styleMask:style backing:NSBackingStoreBuffered defer:NO screen:[nswindow screen]];
1483  [data->nswindow setContentView:[nswindow contentView]];
1484  [data->nswindow registerForDraggedTypes:[NSArray arrayWithObject:(NSString *)kUTTypeFileURL]];
1485  /* See comment in SetupWindowData. */
1486  [data->nswindow setOneShot:NO];
1487  [data->listener listen:data];
1488 
1489  [nswindow close];
1490 
1491  return data->nswindow;
1492 }
1493 
1494 void
1495 Cocoa_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
1496 { @autoreleasepool
1497 {
1498  if (SetWindowStyle(window, GetWindowStyle(window))) {
1499  if (bordered) {
1500  Cocoa_SetWindowTitle(_this, window); /* this got blanked out. */
1501  }
1502  }
1503 }}
1504 
1505 
1506 void
1507 Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
1508 { @autoreleasepool
1509 {
1510  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1511  NSWindow *nswindow = data->nswindow;
1512  NSRect rect;
1513 
1514  /* The view responder chain gets messed with during setStyleMask */
1515  if ([[nswindow contentView] nextResponder] == data->listener) {
1516  [[nswindow contentView] setNextResponder:nil];
1517  }
1518 
1519  if (fullscreen) {
1520  SDL_Rect bounds;
1521 
1522  Cocoa_GetDisplayBounds(_this, display, &bounds);
1523  rect.origin.x = bounds.x;
1524  rect.origin.y = bounds.y;
1525  rect.size.width = bounds.w;
1526  rect.size.height = bounds.h;
1527  ConvertNSRect([nswindow screen], fullscreen, &rect);
1528 
1529  /* Hack to fix origin on Mac OS X 10.4 */
1530  NSRect screenRect = [[nswindow screen] frame];
1531  if (screenRect.size.height >= 1.0f) {
1532  rect.origin.y += (screenRect.size.height - rect.size.height);
1533  }
1534 
1535  if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
1536  [nswindow performSelector: @selector(setStyleMask:) withObject: (id)NSBorderlessWindowMask];
1537  } else {
1538  nswindow = Cocoa_RebuildWindow(data, nswindow, NSBorderlessWindowMask);
1539  }
1540  } else {
1541  rect.origin.x = window->windowed.x;
1542  rect.origin.y = window->windowed.y;
1543  rect.size.width = window->windowed.w;
1544  rect.size.height = window->windowed.h;
1545  ConvertNSRect([nswindow screen], fullscreen, &rect);
1546 
1547  if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
1548  [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)GetWindowStyle(window)];
1549 
1550  /* Hack to restore window decorations on Mac OS X 10.10 */
1551  NSRect frameRect = [nswindow frame];
1552  [nswindow setFrame:NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width + 1, frameRect.size.height) display:NO];
1553  [nswindow setFrame:frameRect display:NO];
1554  } else {
1555  nswindow = Cocoa_RebuildWindow(data, nswindow, GetWindowStyle(window));
1556  }
1557  }
1558 
1559  /* The view responder chain gets messed with during setStyleMask */
1560  if ([[nswindow contentView] nextResponder] != data->listener) {
1561  [[nswindow contentView] setNextResponder:data->listener];
1562  }
1563 
1564  s_moveHack = 0;
1565  [nswindow setContentSize:rect.size];
1566  [nswindow setFrameOrigin:rect.origin];
1567  s_moveHack = SDL_GetTicks();
1568 
1569  /* When the window style changes the title is cleared */
1570  if (!fullscreen) {
1571  Cocoa_SetWindowTitle(_this, window);
1572  }
1573 
1574  if (SDL_ShouldAllowTopmost() && fullscreen) {
1575  /* OpenGL is rendering to the window, so make it visible! */
1576  [nswindow setLevel:CGShieldingWindowLevel()];
1577  } else {
1578  [nswindow setLevel:kCGNormalWindowLevel];
1579  }
1580 
1581  if ([nswindow isVisible] || fullscreen) {
1582  [data->listener pauseVisibleObservation];
1583  [nswindow makeKeyAndOrderFront:nil];
1584  [data->listener resumeVisibleObservation];
1585  }
1586 
1587  ScheduleContextUpdates(data);
1588 }}
1589 
1590 int
1591 Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
1592 {
1593  SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
1594  CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
1595  const uint32_t tableSize = 256;
1596  CGGammaValue redTable[tableSize];
1597  CGGammaValue greenTable[tableSize];
1598  CGGammaValue blueTable[tableSize];
1599  uint32_t i;
1600  float inv65535 = 1.0f / 65535.0f;
1601 
1602  /* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */
1603  for (i = 0; i < 256; i++) {
1604  redTable[i] = ramp[0*256+i] * inv65535;
1605  greenTable[i] = ramp[1*256+i] * inv65535;
1606  blueTable[i] = ramp[2*256+i] * inv65535;
1607  }
1608 
1609  if (CGSetDisplayTransferByTable(display_id, tableSize,
1610  redTable, greenTable, blueTable) != CGDisplayNoErr) {
1611  return SDL_SetError("CGSetDisplayTransferByTable()");
1612  }
1613  return 0;
1614 }
1615 
1616 int
1618 {
1619  SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
1620  CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
1621  const uint32_t tableSize = 256;
1622  CGGammaValue redTable[tableSize];
1623  CGGammaValue greenTable[tableSize];
1624  CGGammaValue blueTable[tableSize];
1625  uint32_t i, tableCopied;
1626 
1627  if (CGGetDisplayTransferByTable(display_id, tableSize,
1628  redTable, greenTable, blueTable, &tableCopied) != CGDisplayNoErr) {
1629  return SDL_SetError("CGGetDisplayTransferByTable()");
1630  }
1631 
1632  for (i = 0; i < tableCopied; i++) {
1633  ramp[0*256+i] = (Uint16)(redTable[i] * 65535.0f);
1634  ramp[1*256+i] = (Uint16)(greenTable[i] * 65535.0f);
1635  ramp[2*256+i] = (Uint16)(blueTable[i] * 65535.0f);
1636  }
1637  return 0;
1638 }
1639 
1640 void
1641 Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
1642 {
1643  /* Move the cursor to the nearest point in the window */
1644  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1645  if (grabbed && data && ![data->listener isMoving]) {
1646  int x, y;
1647  CGPoint cgpoint;
1648 
1649  SDL_GetMouseState(&x, &y);
1650  cgpoint.x = window->x + x;
1651  cgpoint.y = window->y + y;
1652 
1653  Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y);
1654 
1655  DLog("Returning cursor to (%g, %g)", cgpoint.x, cgpoint.y);
1656  CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
1657  }
1658 
1659  if ( data && (window->flags & SDL_WINDOW_FULLSCREEN) ) {
1661  && ![data->listener isInFullscreenSpace]) {
1662  /* OpenGL is rendering to the window, so make it visible! */
1663  /* Doing this in 10.11 while in a Space breaks things (bug #3152) */
1664  [data->nswindow setLevel:CGShieldingWindowLevel()];
1665  } else {
1666  [data->nswindow setLevel:kCGNormalWindowLevel];
1667  }
1668  }
1669 }
1670 
1671 void
1673 { @autoreleasepool
1674 {
1675  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1676 
1677  if (data) {
1678  if ([data->listener isInFullscreenSpace]) {
1679  [NSMenu setMenuBarVisible:YES];
1680  }
1681  [data->listener close];
1682  [data->listener release];
1683  if (data->created) {
1684  [data->nswindow close];
1685  }
1686 
1687  NSArray *contexts = [[data->nscontexts copy] autorelease];
1688  for (SDLOpenGLContext *context in contexts) {
1689  /* Calling setWindow:NULL causes the context to remove itself from the context list. */
1690  [context setWindow:NULL];
1691  }
1692  [data->nscontexts release];
1693 
1694  SDL_free(data);
1695  }
1696  window->driverdata = NULL;
1697 }}
1698 
1699 SDL_bool
1701 {
1702  NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
1703 
1704  if (info->version.major <= SDL_MAJOR_VERSION) {
1705  info->subsystem = SDL_SYSWM_COCOA;
1706  info->info.cocoa.window = nswindow;
1707  return SDL_TRUE;
1708  } else {
1709  SDL_SetError("Application not compiled with SDL %d.%d\n",
1711  return SDL_FALSE;
1712  }
1713 }
1714 
1715 SDL_bool
1716 Cocoa_IsWindowInFullscreenSpace(SDL_Window * window)
1717 {
1718  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1719 
1720  if ([data->listener isInFullscreenSpace]) {
1721  return SDL_TRUE;
1722  } else {
1723  return SDL_FALSE;
1724  }
1725 }
1726 
1727 SDL_bool
1728 Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state)
1729 { @autoreleasepool
1730 {
1731  SDL_bool succeeded = SDL_FALSE;
1732  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1733 
1734  if ([data->listener setFullscreenSpace:(state ? YES : NO)]) {
1735  const int maxattempts = 3;
1736  int attempt = 0;
1737  while (++attempt <= maxattempts) {
1738  /* Wait for the transition to complete, so application changes
1739  take effect properly (e.g. setting the window size, etc.)
1740  */
1741  const int limit = 10000;
1742  int count = 0;
1743  while ([data->listener isInFullscreenSpaceTransition]) {
1744  if ( ++count == limit ) {
1745  /* Uh oh, transition isn't completing. Should we assert? */
1746  break;
1747  }
1748  SDL_Delay(1);
1749  SDL_PumpEvents();
1750  }
1751  if ([data->listener isInFullscreenSpace] == (state ? YES : NO))
1752  break;
1753  /* Try again, the last attempt was interrupted by user gestures */
1754  if (![data->listener setFullscreenSpace:(state ? YES : NO)])
1755  break; /* ??? */
1756  }
1757  /* Return TRUE to prevent non-space fullscreen logic from running */
1758  succeeded = SDL_TRUE;
1759  }
1760 
1761  return succeeded;
1762 }}
1763 
1764 int
1766 {
1767  return 0; /* just succeed, the real work is done elsewhere. */
1768 }
1769 
1770 #endif /* SDL_VIDEO_DRIVER_COCOA */
1771 
1772 /* vi: set ts=4 sw=4 expandtab: */
int Cocoa_CreateWindowFrom(_THIS, SDL_Window *window, const void *data)
#define SDL_MINOR_VERSION
Definition: SDL_version.h:61
GLint limit
GLdouble GLdouble GLdouble r
Definition: SDL_opengl.h:2072
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:66
NSMutableArray * nscontexts
#define SDL_IsShapedWindow
SDL_Texture * button
void SDL_SetKeyboardFocus(SDL_Window *window)
Definition: SDL_keyboard.c:612
void Cocoa_MinimizeWindow(_THIS, SDL_Window *window)
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:155
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 Uint32 * e
void * hit_test_data
Definition: SDL_sysvideo.h:102
void Cocoa_SetWindowIcon(_THIS, SDL_Window *window, SDL_Surface *icon)
#define SDL_MAJOR_VERSION
Definition: SDL_version.h:60
SDL_bool relative_mode_warp
Definition: SDL_mouse_c.h:85
void Cocoa_SetWindowMaximumSize(_THIS, SDL_Window *window)
SDL_Window * focus
Definition: SDL_mouse_c.h:77
Sint64 SDL_FingerID
Definition: SDL_touch.h:42
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1564
SDL_Rect rect
Definition: testrelative.c:27
int(* SetRelativeMouseMode)(SDL_bool enabled)
Definition: SDL_mouse_c.h:67
SDL_Window * window
void Cocoa_SetWindowBordered(_THIS, SDL_Window *window, SDL_bool bordered)
#define SDL_BUTTON_RIGHT
Definition: SDL_mouse.h:282
#define SDL_GetTouchFinger
The structure that defines a point.
Definition: SDL_rect.h:48
A collection of pixels used in software blitting.
Definition: SDL_surface.h:69
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
#define SDL_GetHint
int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, float x, float y, float pressure)
Definition: SDL_touch.c:216
SDL_version version
Definition: SDL_syswm.h:183
Uint8 major
Definition: SDL_version.h:53
GLfloat f
SDL_bool is_destroying
Definition: SDL_sysvideo.h:97
#define SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK
A variable that determines whether ctrl+click should generate a right-click event on Mac...
Definition: SDL_hints.h:387
SDL_SYSWM_TYPE subsystem
Definition: SDL_syswm.h:184
void Cocoa_SetWindowTitle(_THIS, SDL_Window *window)
GLsizei GLenum GLenum * types
int SDL_SendWindowEvent(SDL_Window *window, Uint8 windowevent, int data1, int data2)
SDL_Window * window
void SDL_SetMouseFocus(SDL_Window *window)
Definition: SDL_mouse.c:103
void Cocoa_HandleMouseWarp(CGFloat x, CGFloat y)
#define SDL_GetKeyboardFocus
void Cocoa_SetWindowPosition(_THIS, SDL_Window *window)
unsigned int modifierFlags
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1567
SDL_Rect windowed
Definition: SDL_sysvideo.h:85
GLsizeiptr size
int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, float x, float y, float pressure)
Definition: SDL_touch.c:278
#define SDL_PumpEvents
static SDL_VideoDevice * _this
Definition: SDL_video.c:114
SDL_HitTestResult
Possible return values from the SDL_HitTest callback.
Definition: SDL_video.h:852
SDL_bool
Definition: SDL_stdinc.h:126
void Cocoa_RestoreWindow(_THIS, SDL_Window *window)
int x
Definition: SDL_rect.h:50
BOOL isInFullscreenSpaceTransition()
void Cocoa_ShowWindow(_THIS, SDL_Window *window)
void * SDL_calloc(size_t nmemb, size_t size)
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1565
NSImage * Cocoa_CreateImage(SDL_Surface *surface)
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:188
#define SDL_BUTTON_LEFT
Definition: SDL_mouse.h:280
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
Cocoa_WindowListener * listener
#define _THIS
struct SDL_VideoData * videodata
struct _cl_event * event
void SDL_free(void *mem)
int Cocoa_SetWindowGammaRamp(_THIS, SDL_Window *window, const Uint16 *ramp)
void Cocoa_DestroyWindow(_THIS, SDL_Window *window)
GLint location
void Cocoa_RaiseWindow(_THIS, SDL_Window *window)
SDL_bool cursor_shown
Definition: SDL_mouse_c.h:94
SDL_bool relative_mode
Definition: SDL_mouse_c.h:84
SDL_bool Cocoa_GetWindowWMInfo(_THIS, SDL_Window *window, struct SDL_SysWMinfo *info)
void Cocoa_CheckClipboardUpdate(struct SDL_VideoData *data)
SDL_WindowData * _data
Sint64 SDL_TouchID
Definition: SDL_touch.h:41
void Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event)
#define SDL_BUTTON_MIDDLE
Definition: SDL_mouse.h:281
PendingWindowOperation
char * title
Definition: SDL_sysvideo.h:75
#define SDL_GetNumTouchFingers
int x
Definition: SDL_rect.h:66
int SDL_AddTouch(SDL_TouchID touchID, const char *name)
Definition: SDL_touch.c:130
int w
Definition: SDL_rect.h:67
void Cocoa_SetWindowFullscreen(_THIS, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen)
int(* WarpMouseGlobal)(int x, int y)
Definition: SDL_mouse_c.h:64
NSWindow * nswindow
#define SDL_Delay
GLenum GLenum GLsizei const GLuint GLboolean enabled
void SDL_ToggleModState(const SDL_Keymod modstate, const SDL_bool toggle)
Definition: SDL_keyboard.c:850
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:42
#define SDL_assert(condition)
Definition: SDL_assert.h:167
PendingWindowOperation pendingWindowOperation
Window window
Definition: SDL_syswm.h:204
SDL_bool SDL_ShouldAllowTopmost(void)
Definition: SDL_video.c:3619
#define NULL
Definition: begin_code.h:143
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_GetMouseFocus
SDL_HitTest hit_test
Definition: SDL_sysvideo.h:101
unsigned int uint32_t
Uint32 last_fullscreen_flags
Definition: SDL_sysvideo.h:82
#define SDL_SetError
int Cocoa_CreateWindow(_THIS, SDL_Window *window)
int Cocoa_GetWindowGammaRamp(_THIS, SDL_Window *window, Uint16 *ramp)
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1567
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
Definition: SDL_video.c:1039
int h
Definition: SDL_rect.h:67
#define SDL_strdup
int SDL_SendDropFile(const char *file)
The type used to identify a window.
Definition: SDL_sysvideo.h:71
void Cocoa_SetWindowSize(_THIS, SDL_Window *window)
int Cocoa_ResizeWindowShape(SDL_Window *window)
uint16_t Uint16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:147
SDL_VideoDevice * SDL_GetVideoDevice(void)
Definition: SDL_video.c:573
union SDL_SysWMinfo::@18 info
GLenum array
SDL_FingerID id
Definition: SDL_touch.h:46
GLsizei const GLchar *const * path
GLubyte GLubyte GLubyte GLubyte w
void Cocoa_HideWindow(_THIS, SDL_Window *window)
int Cocoa_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)
void * driverdata
Definition: SDL_sysvideo.h:106
#define FULLSCREEN_MASK
Definition: SDL_video.c:138
void Cocoa_SetWindowGrab(_THIS, SDL_Window *window, SDL_bool grabbed)
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1564
#define SDL_PRESSED
Definition: SDL_events.h:50
SDL_Cursor * cur_cursor
Definition: SDL_mouse_c.h:93
Uint32 flags
Definition: SDL_sysvideo.h:81
#define SDL_RELEASED
Definition: SDL_events.h:49
GLuint in
SDL_Renderer * screen
#define floor
Definition: math_private.h:37
int SDL_SendMouseButton(SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
Definition: SDL_mouse.c:326
int y
Definition: SDL_rect.h:66
#define SDL_GetMouseState
GLfloat GLfloat GLfloat GLfloat h
void Cocoa_MaximizeWindow(_THIS, SDL_Window *window)
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64
int Cocoa_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
void Cocoa_SetWindowMinimumSize(_THIS, SDL_Window *window)