| Summary: | CreateWindowFrom on macOS doesn't work with sub-widgets, only top level window | ||
|---|---|---|---|
| Product: | SDL | Reporter: | michaeljosephmaltese |
| Component: | video | Assignee: | Ryan C. Gordon <icculus> |
| Status: | RESOLVED FIXED | QA Contact: | Sam Lantinga <slouken> |
| Severity: | enhancement | ||
| Priority: | P2 | CC: | icculus, michaeljosephmaltese, sheppy, zebbey |
| Version: | HG 2.1 | Keywords: | target-2.0.14 |
| Hardware: | x86 | ||
| OS: | Mac OS X (All) | ||
| Attachments: | [PATCH] cocoa: allow calling CreateWindowFrom on an NSView | ||
|
Description
michaeljosephmaltese
2020-03-25 23:51:29 UTC
Created attachment 4280 [details]
[PATCH] cocoa: allow calling CreateWindowFrom on an NSView
Here's an attempt at allowing CreateWindowFrom to work with NSViews.
It expands the role of the existing sdlContentView field (caches [nswindow contentView] for created windows, since Cocoa complains if contentview is called off the main thread) to hold the NSView for non-created windows as well. All calls to [nswindow contentView] have been replaced with references to sdlContentView.
When an NSView is passed into CreateWindowFrom, it sets sdlContentView directly, and finds the associated window with [nsview window].
Tested with a basic Qt application, and with testdraw2 and testgl2 from the tests directory.
Comment on attachment 4280 [details] [PATCH] cocoa: allow calling CreateWindowFrom on an NSView # HG changeset patch # User Michael Maltese <michaeljosephmaltese@gmail.com> # Date 1585179643 25200 # Wed Mar 25 16:40:43 2020 -0700 # Node ID aaec3f2027fc1efe5473bbd8477d5860f97487ff # Parent 389ce8cfa2a31f765c3d751c911c73abf5c60e33 cocoa: allow calling CreateWindowFrom on an NSView This lets applications embed SDL with other widgets surrounding it. Already possible on Windows and X11. diff -r 389ce8cfa2a3 -r aaec3f2027fc src/video/cocoa/SDL_cocoaopengl.m --- a/src/video/cocoa/SDL_cocoaopengl.m Wed Mar 25 09:38:45 2020 -0700 +++ b/src/video/cocoa/SDL_cocoaopengl.m Wed Mar 25 16:40:43 2020 -0700 @@ -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) { @@ -362,7 +351,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 -r 389ce8cfa2a3 -r aaec3f2027fc src/video/cocoa/SDL_cocoashape.m --- a/src/video/cocoa/SDL_cocoashape.m Wed Mar 25 09:38:45 2020 -0700 +++ b/src/video/cocoa/SDL_cocoashape.m Wed Mar 25 16:40:43 2020 -0700 @@ -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 -r 389ce8cfa2a3 -r aaec3f2027fc src/video/cocoa/SDL_cocoawindow.h --- a/src/video/cocoa/SDL_cocoawindow.h Wed Mar 25 09:38:45 2020 -0700 +++ b/src/video/cocoa/SDL_cocoawindow.h Wed Mar 25 16:40:43 2020 -0700 @@ -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 -r 389ce8cfa2a3 -r aaec3f2027fc src/video/cocoa/SDL_cocoawindow.m --- a/src/video/cocoa/SDL_cocoawindow.m Wed Mar 25 09:38:45 2020 -0700 +++ b/src/video/cocoa/SDL_cocoawindow.m Wed Mar 25 16:40:43 2020 -0700 @@ -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->sdlContentView; _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; This patch looks promising. I will try to come up with time to try it out myself as well. This looks reasonable to me. I've put it in revision control at https://hg.libsdl.org/SDL/rev/6d22d6ce725c ... Eric, if you want to try it, just get the latest revision of SDL. Thanks! --ryan. I have tried the newest version from the hg repos. The problem has not been resolved.
Here is my test code:
# coding: utf-8
import os
import wx
import sdl2
import sdl2.ext
# import sdl2.sdlgfx
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, 'MainFrame', pos=(0, 0), size = (400, 300), style = wx.DEFAULT_FRAME_STYLE)
self.panelLeft = wx.Panel(self, style=wx.BORDER_SUNKEN)
self.panelRight = wx.Panel(self, style=wx.BORDER_SUNKEN)
sizer = wx.BoxSizer()
sizer.Add(self.panelLeft, 1, wx.ALL|wx.EXPAND, border=10)
sizer.Add(self.panelRight, 1, wx.ALL|wx.EXPAND, border=10)
self.SetSizer(sizer)
sdl2.ext.init()
self.window = sdl2.SDL_CreateWindowFrom(self.panelRight.GetHandle())
self.renderer = sdl2.SDL_CreateRenderer(self.window, -1, sdl2.SDL_RENDERER_ACCELERATED)
sdl2.SDL_SetHint(sdl2.hints.SDL_HINT_RENDER_SCALE_QUALITY, b"1")
self.Bind(wx.EVT_IDLE, self.render)
def render(self, e):
sdl2.SDL_SetRenderDrawColor(self.renderer, 225, 0, 0, 255)
sdl2.SDL_RenderClear(self.renderer)
# sdl2.sdlgfx.lineRGBA(self.renderer, 0, 0, 100, 100, 255, 255, 255, 255)
sdl2.SDL_RenderPresent(self.renderer)
class App(wx.App):
def OnInit(self):
self.mainFrame = MainFrame()
self.mainFrame.Show(True)
self.mainFrame.CentreOnScreen()
self.SetTopWindow(self.mainFrame)
return True
def getMainFrame(self):
return self._mainFrame
app = App()
app.MainLoop()
The right panel should be filled with red color, but the whole window has beed filled.
@zeb This issue was about CreateWindowFrom not working at all on macOS, leading to crashes or at the least a failure to create a window. That issue has been fixed. What you're writing about is not the same issue: CreateFromWindow gives you a working SDL window (what this bug fixed), just not the one you want (not part of this but). Honestly it sounds like a wxWidgets issue not giving an NSView for the widget you want. I'm reclosing this — if you need support for your issue, please take it to the forums. (If in the end it is determined to be an SDL issue, then please create a _new_ bug.) . |