Using the native Cocoa NSWindow handle seems erratic and results in crashes on macOS with SDL 2.32.10
Problem description
This is a simplified repro case of something I'm working on in a bigger project. Basically, I want to re-tag the window with [window setColorSpace: [NSColorSpace displayP3ColorSpace]] on macOS because SDL hardcodes this to sRGBColorSpace which is a problem.
In the large project re-tagging the color space works if I do it right after the window creation from the same function. Yep, it's super weird. If I do it any differently, I'd get a crash...
Now, I need to re-tag the window's color space sometimes, and that always results in a crash, no matter what I do. For more context, the app replaces the existing SDL_GLContext context and uses SDL_CreateRenderer to draw some stuff, then restores the GL context (don't ask, it's some piece of shit legacy code...) This process somehow resets the color space tag to sRGBColorSpace again (maybe the window get recreated when mucking around with the SDL_Renderer?), that's why I need to re-tag it with Display P3.
Repro case
I attempted to reproduce the behaviour in a simplified repro case. In this test, [window setColorSpace: [NSColorSpace displayP3ColorSpace]] always results in a crash, so it's even worse than in my larger app.
You can get the repro case from here: https://github.com/johnnovak/minimal-sdl2
I'm pasting the code here as well.
This is the result I'm getting on every single run. I don't think I'm doing anything wrong, this should work, right?
Solutions
- Fix getting the native Cocoa NSWindow handle stuff so I can send messages to the native Cocoa window any time to re-tag the color space (or do anything with the window with native Cocoa calls).
- Introduce a hint to override the hardcoded
sRGBColorSpacewithdisplayP3ColorSpace(that would solve all my problems in a much simpler way).
Thanks 😄
main.cpp
#include <cstdlib>
#include <SDL2/SDL.h>
#include <SDL2/SDL_main.h>
#include <SDL_syswm.h>
#include "cocoa.h"
static auto should_quit = false;
void set_color_space(SDL_Window* window) {
SDL_SysWMinfo wmInfo;
SDL_GetWindowWMInfo(window, &wmInfo);
void* nswindow = wmInfo.info.cocoa.window;
printf("nswindow: %p\n", nswindow);
setDisplayP3ColorSpace(nswindow);
}
int main(int argc, char* argv[]) {
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
printf("Unable to initialize SDL: %s", SDL_GetError());
return EXIT_FAILURE;
}
SDL_version sdl_version = {};
SDL_GetVersion(&sdl_version);
printf("SDL version: %d.%d.%d\n",
sdl_version.major,
sdl_version.minor,
sdl_version.patch);
auto window = SDL_CreateWindow("Example",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
800, 600, 0);
// CRASH!
set_color_space(window);
SDL_RaiseWindow(window);
SDL_Event event;
while (!should_quit) {
while (SDL_PollEvent(&event) > 0) {
switch (event.type) {
case SDL_QUIT: {
should_quit = true;
return;
}
}
}
}
return EXIT_SUCCESS;
}
cocoa.m
#import <Cocoa/Cocoa.h>
void setDisplayP3ColorSpace(void* nswindow)
{
NSWindow* window = nswindow;
[window setColorSpace: [NSColorSpace displayP3ColorSpace]];
}
cocoa.h
extern "C" void setDisplayP3ColorSpace(void* nswindow);
Hmm, it does crash in SDL2, but it seems to work with SDL3:
#include <cstdlib>
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include "cocoa.h"
static auto should_quit = false;
void set_color_space(SDL_Window* window) {
void* nswindow = SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL);
printf("nswindow: %p\n", nswindow);
setDisplayP3ColorSpace(nswindow);
}
int main(int argc, char* argv[]) {
if (!SDL_Init(SDL_INIT_VIDEO)) {
printf("Unable to initialize SDL: %s", SDL_GetError());
return EXIT_FAILURE;
}
auto window = SDL_CreateWindow("Example", 800, 600, 0);
// CRASH!
set_color_space(window);
SDL_RaiseWindow(window);
SDL_Event event;
while (!should_quit) {
while (SDL_PollEvent(&event) > 0) {
switch (event.type) {
case SDL_EVENT_QUIT: {
should_quit = true;
break;
}
}
}
}
return EXIT_SUCCESS;
}
@slouken Thanks for looking into it so quickly. Unfortunately, we can't upgrade to SDL3 just yet, maybe in a year or so.