cocoa: allow calling CreateWindowFrom on an NSView
authorMichael Maltese
Wed, 25 Mar 2020 16:40:43 -0700
changeset 137056d22d6ce725c
parent 13704 25edf3df6e51
child 13706 41280cc79f3d
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.
src/video/cocoa/SDL_cocoaopengl.m
src/video/cocoa/SDL_cocoashape.m
src/video/cocoa/SDL_cocoawindow.h
src/video/cocoa/SDL_cocoawindow.m
     1.1 --- a/src/video/cocoa/SDL_cocoaopengl.m	Tue Apr 07 14:03:13 2020 -0400
     1.2 +++ b/src/video/cocoa/SDL_cocoaopengl.m	Wed Mar 25 16:40:43 2020 -0700
     1.3 @@ -97,17 +97,6 @@
     1.4          SDL_WindowData *windowdata = (SDL_WindowData *)newWindow->driverdata;
     1.5          NSView *contentview = windowdata->sdlContentView;
     1.6  
     1.7 -        /* This should never be nil since sdlContentView is only nil if the
     1.8 -           window was created via SDL_CreateWindowFrom, and SDL doesn't allow
     1.9 -           OpenGL contexts to be created in that case. However, it doesn't hurt
    1.10 -           to check. */
    1.11 -        if (contentview == nil) {
    1.12 -            /* Prefer to access the cached content view above instead of this,
    1.13 -               since as of Xcode 11 + SDK 10.15, [window contentView] causes
    1.14 -               Apple's Main Thread Checker to output a warning. */
    1.15 -            contentview = [windowdata->nswindow contentView];
    1.16 -        }
    1.17 -
    1.18          /* Now sign up for scheduled updates for the new window. */
    1.19          NSMutableArray *contexts = windowdata->nscontexts;
    1.20          @synchronized (contexts) {
    1.21 @@ -382,7 +371,7 @@
    1.22  Cocoa_GL_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
    1.23  {
    1.24      SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
    1.25 -    NSView *contentView = [windata->nswindow contentView];
    1.26 +    NSView *contentView = windata->sdlContentView;
    1.27      NSRect viewport = [contentView bounds];
    1.28  
    1.29      if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
     2.1 --- a/src/video/cocoa/SDL_cocoashape.m	Tue Apr 07 14:03:13 2020 -0400
     2.2 +++ b/src/video/cocoa/SDL_cocoashape.m	Wed Mar 25 16:40:43 2020 -0700
     2.3 @@ -88,10 +88,10 @@
     2.4      [NSGraphicsContext setCurrentContext:data->context];
     2.5  
     2.6      [[NSColor clearColor] set];
     2.7 -    NSRectFill([[windata->nswindow contentView] frame]);
     2.8 +    NSRectFill([windata->sdlContentView frame]);
     2.9      data->shape = SDL_CalculateShapeTree(*shape_mode,shape);
    2.10  
    2.11 -    closure.view = [windata->nswindow contentView];
    2.12 +    closure.view = windata->sdlContentView;
    2.13      closure.path = [NSBezierPath bezierPath];
    2.14      closure.window = shaper->window;
    2.15      SDL_TraverseShapeTree(data->shape,&ConvertRects,&closure);
     3.1 --- a/src/video/cocoa/SDL_cocoawindow.h	Tue Apr 07 14:03:13 2020 -0400
     3.2 +++ b/src/video/cocoa/SDL_cocoawindow.h	Wed Mar 25 16:40:43 2020 -0700
     3.3 @@ -113,7 +113,7 @@
     3.4  {
     3.5      SDL_Window *window;
     3.6      NSWindow *nswindow;
     3.7 -    NSView *sdlContentView; /* nil if window is created via CreateWindowFrom */
     3.8 +    NSView *sdlContentView;
     3.9      NSMutableArray *nscontexts;
    3.10      SDL_bool created;
    3.11      SDL_bool inWindowFullscreenTransition;
     4.1 --- a/src/video/cocoa/SDL_cocoawindow.m	Tue Apr 07 14:03:13 2020 -0400
     4.2 +++ b/src/video/cocoa/SDL_cocoawindow.m	Wed Mar 25 16:40:43 2020 -0700
     4.3 @@ -297,15 +297,15 @@
     4.4      NSWindow *nswindow = data->nswindow;
     4.5  
     4.6      /* The view responder chain gets messed with during setStyleMask */
     4.7 -    if ([[nswindow contentView] nextResponder] == data->listener) {
     4.8 -        [[nswindow contentView] setNextResponder:nil];
     4.9 +    if ([data->sdlContentView nextResponder] == data->listener) {
    4.10 +        [data->sdlContentView setNextResponder:nil];
    4.11      }
    4.12  
    4.13      [nswindow setStyleMask:style];
    4.14  
    4.15      /* The view responder chain gets messed with during setStyleMask */
    4.16 -    if ([[nswindow contentView] nextResponder] != data->listener) {
    4.17 -        [[nswindow contentView] setNextResponder:data->listener];
    4.18 +    if ([data->sdlContentView nextResponder] != data->listener) {
    4.19 +        [data->sdlContentView setNextResponder:data->listener];
    4.20      }
    4.21  
    4.22      return SDL_TRUE;
    4.23 @@ -318,7 +318,7 @@
    4.24  {
    4.25      NSNotificationCenter *center;
    4.26      NSWindow *window = data->nswindow;
    4.27 -    NSView *view = [window contentView];
    4.28 +    NSView *view = data->nsview;
    4.29  
    4.30      _data = data;
    4.31      observingVisible = YES;
    4.32 @@ -1360,7 +1360,7 @@
    4.33  @end
    4.34  
    4.35  static int
    4.36 -SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created)
    4.37 +SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, NSView *nsview, SDL_bool created)
    4.38  { @autoreleasepool
    4.39  {
    4.40      SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
    4.41 @@ -1376,11 +1376,7 @@
    4.42      data->created = created;
    4.43      data->videodata = videodata;
    4.44      data->nscontexts = [[NSMutableArray alloc] init];
    4.45 -
    4.46 -    /* Only store this for windows created by us since the content view might
    4.47 -     * get replaced from under us otherwise, and we only need it when the
    4.48 -     * window is guaranteed to be created by us (OpenGL contexts). */
    4.49 -    data->sdlContentView = created ? [nswindow contentView] : nil;
    4.50 +    data->sdlContentView = nsview;
    4.51  
    4.52      /* Create an event listener for the window */
    4.53      data->listener = [[Cocoa_WindowListener alloc] init];
    4.54 @@ -1541,7 +1537,7 @@
    4.55      [nswindow setContentView:contentView];
    4.56      [contentView release];
    4.57  
    4.58 -    if (SetupWindowData(_this, window, nswindow, SDL_TRUE) < 0) {
    4.59 +    if (SetupWindowData(_this, window, nswindow, contentView, SDL_TRUE) < 0) {
    4.60          [nswindow release];
    4.61          return -1;
    4.62      }
    4.63 @@ -1571,7 +1567,19 @@
    4.64  Cocoa_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
    4.65  { @autoreleasepool
    4.66  {
    4.67 -    NSWindow *nswindow = (NSWindow *) data;
    4.68 +    NSView* nsview;
    4.69 +    NSWindow *nswindow;
    4.70 +
    4.71 +    if ([(id)data isKindOfClass:[NSWindow class]]) {
    4.72 +      nswindow = (NSWindow*)data;
    4.73 +      nsview = [nswindow contentView];
    4.74 +    } else if ([(id)data isKindOfClass:[NSView class]]) {
    4.75 +      nsview = (NSView*)data;
    4.76 +      nswindow = [nsview window];
    4.77 +    } else {
    4.78 +      SDL_assert(false);
    4.79 +    }
    4.80 +
    4.81      NSString *title;
    4.82  
    4.83      /* Query the title from the existing window */
    4.84 @@ -1580,7 +1588,7 @@
    4.85          window->title = SDL_strdup([title UTF8String]);
    4.86      }
    4.87  
    4.88 -    return SetupWindowData(_this, window, nswindow, SDL_FALSE);
    4.89 +    return SetupWindowData(_this, window, nswindow, nsview, SDL_FALSE);
    4.90  }}
    4.91  
    4.92  void
    4.93 @@ -1795,8 +1803,8 @@
    4.94      NSRect rect;
    4.95  
    4.96      /* The view responder chain gets messed with during setStyleMask */
    4.97 -    if ([[nswindow contentView] nextResponder] == data->listener) {
    4.98 -        [[nswindow contentView] setNextResponder:nil];
    4.99 +    if ([data->sdlContentView nextResponder] == data->listener) {
   4.100 +        [data->sdlContentView setNextResponder:nil];
   4.101      }
   4.102  
   4.103      if (fullscreen) {
   4.104 @@ -1852,8 +1860,8 @@
   4.105      }
   4.106  
   4.107      /* The view responder chain gets messed with during setStyleMask */
   4.108 -    if ([[nswindow contentView] nextResponder] != data->listener) {
   4.109 -        [[nswindow contentView] setNextResponder:data->listener];
   4.110 +    if ([data->sdlContentView nextResponder] != data->listener) {
   4.111 +        [data->sdlContentView setNextResponder:data->listener];
   4.112      }
   4.113  
   4.114      s_moveHack = 0;