cocoa: allow calling CreateWindowFrom on an NSView

This lets applications embed SDL with other widgets surrounding it.
Already possible on Windows and X11.

Fixes Bugzilla #5060.

--HG--
extra : rebase_source : 4e31c8c5b15cf001b3f4eae63d79e1620b351b67
diff --git a/src/video/cocoa/SDL_cocoaopengl.m b/src/video/cocoa/SDL_cocoaopengl.m
index 257f1a5..6fb4711 100644
--- a/src/video/cocoa/SDL_cocoaopengl.m
+++ b/src/video/cocoa/SDL_cocoaopengl.m
@@ -97,17 +97,6 @@
         SDL_WindowData *windowdata = (SDL_WindowData *)newWindow->driverdata;
         NSView *contentview = windowdata->sdlContentView;
 
-        /* This should never be nil since sdlContentView is only nil if the
-           window was created via SDL_CreateWindowFrom, and SDL doesn't allow
-           OpenGL contexts to be created in that case. However, it doesn't hurt
-           to check. */
-        if (contentview == nil) {
-            /* Prefer to access the cached content view above instead of this,
-               since as of Xcode 11 + SDK 10.15, [window contentView] causes
-               Apple's Main Thread Checker to output a warning. */
-            contentview = [windowdata->nswindow contentView];
-        }
-
         /* Now sign up for scheduled updates for the new window. */
         NSMutableArray *contexts = windowdata->nscontexts;
         @synchronized (contexts) {
@@ -382,7 +371,7 @@
 Cocoa_GL_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
 {
     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
-    NSView *contentView = [windata->nswindow contentView];
+    NSView *contentView = windata->sdlContentView;
     NSRect viewport = [contentView bounds];
 
     if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
diff --git a/src/video/cocoa/SDL_cocoashape.m b/src/video/cocoa/SDL_cocoashape.m
index 8a43c11..e889835 100644
--- a/src/video/cocoa/SDL_cocoashape.m
+++ b/src/video/cocoa/SDL_cocoashape.m
@@ -88,10 +88,10 @@
     [NSGraphicsContext setCurrentContext:data->context];
 
     [[NSColor clearColor] set];
-    NSRectFill([[windata->nswindow contentView] frame]);
+    NSRectFill([windata->sdlContentView frame]);
     data->shape = SDL_CalculateShapeTree(*shape_mode,shape);
 
-    closure.view = [windata->nswindow contentView];
+    closure.view = windata->sdlContentView;
     closure.path = [NSBezierPath bezierPath];
     closure.window = shaper->window;
     SDL_TraverseShapeTree(data->shape,&ConvertRects,&closure);
diff --git a/src/video/cocoa/SDL_cocoawindow.h b/src/video/cocoa/SDL_cocoawindow.h
index 049d00f..4c0570f 100644
--- a/src/video/cocoa/SDL_cocoawindow.h
+++ b/src/video/cocoa/SDL_cocoawindow.h
@@ -113,7 +113,7 @@
 {
     SDL_Window *window;
     NSWindow *nswindow;
-    NSView *sdlContentView; /* nil if window is created via CreateWindowFrom */
+    NSView *sdlContentView;
     NSMutableArray *nscontexts;
     SDL_bool created;
     SDL_bool inWindowFullscreenTransition;
diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m
index 297fef0..bde2ed8 100644
--- a/src/video/cocoa/SDL_cocoawindow.m
+++ b/src/video/cocoa/SDL_cocoawindow.m
@@ -297,15 +297,15 @@
     NSWindow *nswindow = data->nswindow;
 
     /* The view responder chain gets messed with during setStyleMask */
-    if ([[nswindow contentView] nextResponder] == data->listener) {
-        [[nswindow contentView] setNextResponder:nil];
+    if ([data->sdlContentView nextResponder] == data->listener) {
+        [data->sdlContentView setNextResponder:nil];
     }
 
     [nswindow setStyleMask:style];
 
     /* The view responder chain gets messed with during setStyleMask */
-    if ([[nswindow contentView] nextResponder] != data->listener) {
-        [[nswindow contentView] setNextResponder:data->listener];
+    if ([data->sdlContentView nextResponder] != data->listener) {
+        [data->sdlContentView setNextResponder:data->listener];
     }
 
     return SDL_TRUE;
@@ -318,7 +318,7 @@
 {
     NSNotificationCenter *center;
     NSWindow *window = data->nswindow;
-    NSView *view = [window contentView];
+    NSView *view = data->nsview;
 
     _data = data;
     observingVisible = YES;
@@ -1360,7 +1360,7 @@
 @end
 
 static int
-SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created)
+SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, NSView *nsview, SDL_bool created)
 { @autoreleasepool
 {
     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
@@ -1376,11 +1376,7 @@
     data->created = created;
     data->videodata = videodata;
     data->nscontexts = [[NSMutableArray alloc] init];
-
-    /* Only store this for windows created by us since the content view might
-     * get replaced from under us otherwise, and we only need it when the
-     * window is guaranteed to be created by us (OpenGL contexts). */
-    data->sdlContentView = created ? [nswindow contentView] : nil;
+    data->sdlContentView = nsview;
 
     /* Create an event listener for the window */
     data->listener = [[Cocoa_WindowListener alloc] init];
@@ -1541,7 +1537,7 @@
     [nswindow setContentView:contentView];
     [contentView release];
 
-    if (SetupWindowData(_this, window, nswindow, SDL_TRUE) < 0) {
+    if (SetupWindowData(_this, window, nswindow, contentView, SDL_TRUE) < 0) {
         [nswindow release];
         return -1;
     }
@@ -1571,7 +1567,19 @@
 Cocoa_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
 { @autoreleasepool
 {
-    NSWindow *nswindow = (NSWindow *) data;
+    NSView* nsview;
+    NSWindow *nswindow;
+
+    if ([(id)data isKindOfClass:[NSWindow class]]) {
+      nswindow = (NSWindow*)data;
+      nsview = [nswindow contentView];
+    } else if ([(id)data isKindOfClass:[NSView class]]) {
+      nsview = (NSView*)data;
+      nswindow = [nsview window];
+    } else {
+      SDL_assert(false);
+    }
+
     NSString *title;
 
     /* Query the title from the existing window */
@@ -1580,7 +1588,7 @@
         window->title = SDL_strdup([title UTF8String]);
     }
 
-    return SetupWindowData(_this, window, nswindow, SDL_FALSE);
+    return SetupWindowData(_this, window, nswindow, nsview, SDL_FALSE);
 }}
 
 void
@@ -1795,8 +1803,8 @@
     NSRect rect;
 
     /* The view responder chain gets messed with during setStyleMask */
-    if ([[nswindow contentView] nextResponder] == data->listener) {
-        [[nswindow contentView] setNextResponder:nil];
+    if ([data->sdlContentView nextResponder] == data->listener) {
+        [data->sdlContentView setNextResponder:nil];
     }
 
     if (fullscreen) {
@@ -1852,8 +1860,8 @@
     }
 
     /* The view responder chain gets messed with during setStyleMask */
-    if ([[nswindow contentView] nextResponder] != data->listener) {
-        [[nswindow contentView] setNextResponder:data->listener];
+    if ([data->sdlContentView nextResponder] != data->listener) {
+        [data->sdlContentView setNextResponder:data->listener];
     }
 
     s_moveHack = 0;