Atlas - SDL_cocoavideo.m

Home / ext / SDL / src / video / cocoa Lines: 1 | Size: 12676 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 Sam Lantinga <[email protected]> 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#ifdef SDL_VIDEO_DRIVER_COCOA 24 25#if !__has_feature(objc_arc) 26#error SDL must be built with Objective-C ARC (automatic reference counting) enabled 27#endif 28 29#include "SDL_cocoavideo.h" 30#include "SDL_cocoavulkan.h" 31#include "SDL_cocoametalview.h" 32#include "SDL_cocoaopengles.h" 33#include "SDL_cocoamessagebox.h" 34#include "SDL_cocoashape.h" 35 36#include "../../events/SDL_keyboard_c.h" 37#include "../../events/SDL_mouse_c.h" 38 39@implementation SDL_CocoaVideoData 40 41@end 42 43// Initialization/Query functions 44static bool Cocoa_VideoInit(SDL_VideoDevice *_this); 45static void Cocoa_VideoQuit(SDL_VideoDevice *_this); 46 47// Cocoa driver bootstrap functions 48 49static void Cocoa_DeleteDevice(SDL_VideoDevice *device) 50{ 51 @autoreleasepool { 52 CFBridgingRelease(device->internal); 53 SDL_free(device); 54 } 55} 56 57static SDL_VideoDevice *Cocoa_CreateDevice(void) 58{ 59 @autoreleasepool { 60 SDL_VideoDevice *device; 61 SDL_CocoaVideoData *data; 62 63 if (![NSThread isMainThread]) { 64 return NULL; // this doesn't SDL_SetError() because SDL_VideoInit is just going to overwrite it. 65 } 66 67 Cocoa_RegisterApp(); 68 69 // Initialize all variables that we clean on shutdown 70 device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice)); 71 if (device) { 72 data = [[SDL_CocoaVideoData alloc] init]; 73 } else { 74 data = nil; 75 } 76 if (!data) { 77 SDL_free(device); 78 return NULL; 79 } 80 device->internal = (SDL_VideoData *)CFBridgingRetain(data); 81 device->system_theme = Cocoa_GetSystemTheme(); 82 83 // Set the function pointers 84 device->VideoInit = Cocoa_VideoInit; 85 device->VideoQuit = Cocoa_VideoQuit; 86 device->GetDisplayBounds = Cocoa_GetDisplayBounds; 87 device->GetDisplayUsableBounds = Cocoa_GetDisplayUsableBounds; 88 device->GetDisplayModes = Cocoa_GetDisplayModes; 89 device->SetDisplayMode = Cocoa_SetDisplayMode; 90 device->PumpEvents = Cocoa_PumpEvents; 91 device->WaitEventTimeout = Cocoa_WaitEventTimeout; 92 device->SendWakeupEvent = Cocoa_SendWakeupEvent; 93 device->SuspendScreenSaver = Cocoa_SuspendScreenSaver; 94 95 device->CreateSDLWindow = Cocoa_CreateWindow; 96 device->SetWindowTitle = Cocoa_SetWindowTitle; 97 device->SetWindowIcon = Cocoa_SetWindowIcon; 98 device->SetWindowPosition = Cocoa_SetWindowPosition; 99 device->SetWindowSize = Cocoa_SetWindowSize; 100 device->SetWindowMinimumSize = Cocoa_SetWindowMinimumSize; 101 device->SetWindowMaximumSize = Cocoa_SetWindowMaximumSize; 102 device->SetWindowAspectRatio = Cocoa_SetWindowAspectRatio; 103 device->SetWindowOpacity = Cocoa_SetWindowOpacity; 104 device->GetWindowSizeInPixels = Cocoa_GetWindowSizeInPixels; 105 device->ShowWindow = Cocoa_ShowWindow; 106 device->HideWindow = Cocoa_HideWindow; 107 device->RaiseWindow = Cocoa_RaiseWindow; 108 device->MaximizeWindow = Cocoa_MaximizeWindow; 109 device->MinimizeWindow = Cocoa_MinimizeWindow; 110 device->RestoreWindow = Cocoa_RestoreWindow; 111 device->SetWindowBordered = Cocoa_SetWindowBordered; 112 device->SetWindowResizable = Cocoa_SetWindowResizable; 113 device->SetWindowAlwaysOnTop = Cocoa_SetWindowAlwaysOnTop; 114 device->SetWindowFullscreen = Cocoa_SetWindowFullscreen; 115 device->GetWindowICCProfile = Cocoa_GetWindowICCProfile; 116 device->GetDisplayForWindow = Cocoa_GetDisplayForWindow; 117 device->SetWindowMouseRect = Cocoa_SetWindowMouseRect; 118 device->SetWindowMouseGrab = Cocoa_SetWindowMouseGrab; 119 device->SetWindowKeyboardGrab = Cocoa_SetWindowKeyboardGrab; 120 device->DestroyWindow = Cocoa_DestroyWindow; 121 device->SetWindowHitTest = Cocoa_SetWindowHitTest; 122 device->AcceptDragAndDrop = Cocoa_AcceptDragAndDrop; 123 device->UpdateWindowShape = Cocoa_UpdateWindowShape; 124 device->FlashWindow = Cocoa_FlashWindow; 125 device->SetWindowFocusable = Cocoa_SetWindowFocusable; 126 device->SetWindowParent = Cocoa_SetWindowParent; 127 device->SetWindowModal = Cocoa_SetWindowModal; 128 device->SyncWindow = Cocoa_SyncWindow; 129 130#ifdef SDL_VIDEO_OPENGL_CGL 131 device->GL_LoadLibrary = Cocoa_GL_LoadLibrary; 132 device->GL_GetProcAddress = Cocoa_GL_GetProcAddress; 133 device->GL_UnloadLibrary = Cocoa_GL_UnloadLibrary; 134 device->GL_CreateContext = Cocoa_GL_CreateContext; 135 device->GL_MakeCurrent = Cocoa_GL_MakeCurrent; 136 device->GL_SetSwapInterval = Cocoa_GL_SetSwapInterval; 137 device->GL_GetSwapInterval = Cocoa_GL_GetSwapInterval; 138 device->GL_SwapWindow = Cocoa_GL_SwapWindow; 139 device->GL_DestroyContext = Cocoa_GL_DestroyContext; 140 device->GL_GetEGLSurface = NULL; 141#endif 142#ifdef SDL_VIDEO_OPENGL_EGL 143#ifdef SDL_VIDEO_OPENGL_CGL 144 if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, false)) { 145#endif 146 device->GL_LoadLibrary = Cocoa_GLES_LoadLibrary; 147 device->GL_GetProcAddress = Cocoa_GLES_GetProcAddress; 148 device->GL_UnloadLibrary = Cocoa_GLES_UnloadLibrary; 149 device->GL_CreateContext = Cocoa_GLES_CreateContext; 150 device->GL_MakeCurrent = Cocoa_GLES_MakeCurrent; 151 device->GL_SetSwapInterval = Cocoa_GLES_SetSwapInterval; 152 device->GL_GetSwapInterval = Cocoa_GLES_GetSwapInterval; 153 device->GL_SwapWindow = Cocoa_GLES_SwapWindow; 154 device->GL_DestroyContext = Cocoa_GLES_DestroyContext; 155 device->GL_GetEGLSurface = Cocoa_GLES_GetEGLSurface; 156#ifdef SDL_VIDEO_OPENGL_CGL 157 } 158#endif 159#endif 160 161#ifdef SDL_VIDEO_VULKAN 162 device->Vulkan_LoadLibrary = Cocoa_Vulkan_LoadLibrary; 163 device->Vulkan_UnloadLibrary = Cocoa_Vulkan_UnloadLibrary; 164 device->Vulkan_GetInstanceExtensions = Cocoa_Vulkan_GetInstanceExtensions; 165 device->Vulkan_CreateSurface = Cocoa_Vulkan_CreateSurface; 166 device->Vulkan_DestroySurface = Cocoa_Vulkan_DestroySurface; 167#endif 168 169#ifdef SDL_VIDEO_METAL 170 device->Metal_CreateView = Cocoa_Metal_CreateView; 171 device->Metal_DestroyView = Cocoa_Metal_DestroyView; 172 device->Metal_GetLayer = Cocoa_Metal_GetLayer; 173#endif 174 175 device->StartTextInput = Cocoa_StartTextInput; 176 device->StopTextInput = Cocoa_StopTextInput; 177 device->UpdateTextInputArea = Cocoa_UpdateTextInputArea; 178 179 device->SetClipboardData = Cocoa_SetClipboardData; 180 device->GetClipboardData = Cocoa_GetClipboardData; 181 device->HasClipboardData = Cocoa_HasClipboardData; 182 183 device->free = Cocoa_DeleteDevice; 184 185 device->device_caps = VIDEO_DEVICE_CAPS_HAS_POPUP_WINDOW_SUPPORT | 186 VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS; 187 return device; 188 } 189} 190 191VideoBootStrap COCOA_bootstrap = { 192 "cocoa", "SDL Cocoa video driver", 193 Cocoa_CreateDevice, 194 Cocoa_ShowMessageBox, 195 false 196}; 197 198static bool Cocoa_VideoInit(SDL_VideoDevice *_this) 199{ 200 @autoreleasepool { 201 SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal; 202 203 Cocoa_InitModes(_this); 204 Cocoa_InitKeyboard(_this); 205 if (!Cocoa_InitMouse(_this)) { 206 return false; 207 } 208 if (!Cocoa_InitPen(_this)) { 209 return false; 210 } 211 212 // Initialize GCMouse for raw input on macOS 11.0+ 213 Cocoa_InitGCMouse(); 214 215 // Add default keyboard and mouse if GCMouse didn't provide any 216 SDL_AddKeyboard(SDL_DEFAULT_KEYBOARD_ID, NULL); 217 if (!Cocoa_HasGCMouse()) { 218 SDL_AddMouse(SDL_DEFAULT_MOUSE_ID, NULL); 219 } 220 221 data.allow_spaces = SDL_GetHintBoolean(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, true); 222 data.trackpad_is_touch_only = SDL_GetHintBoolean(SDL_HINT_TRACKPAD_IS_TOUCH_ONLY, false); 223 SDL_AddHintCallback(SDL_HINT_VIDEO_MAC_FULLSCREEN_MENU_VISIBILITY, Cocoa_MenuVisibilityCallback, NULL); 224 225 data.swaplock = SDL_CreateMutex(); 226 if (!data.swaplock) { 227 return false; 228 } 229 230 return true; 231 } 232} 233 234void Cocoa_VideoQuit(SDL_VideoDevice *_this) 235{ 236 @autoreleasepool { 237 SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal; 238 Cocoa_QuitModes(_this); 239 Cocoa_QuitKeyboard(_this); 240 Cocoa_QuitGCMouse(); 241 Cocoa_QuitMouse(_this); 242 Cocoa_QuitPen(_this); 243 SDL_DestroyMutex(data.swaplock); 244 data.swaplock = NULL; 245 } 246} 247 248// This function assumes that it's called from within an autorelease pool 249SDL_SystemTheme Cocoa_GetSystemTheme(void) 250{ 251 if (@available(macOS 10.14, *)) { 252 NSAppearance *appearance = [[NSApplication sharedApplication] effectiveAppearance]; 253 254 if ([appearance.name containsString: @"Dark"]) { 255 return SDL_SYSTEM_THEME_DARK; 256 } 257 } 258 return SDL_SYSTEM_THEME_LIGHT; 259} 260 261// This function assumes that it's called from within an autorelease pool 262NSImage *Cocoa_CreateImage(SDL_Surface *surface) 263{ 264 NSImage *img; 265 266 img = [[NSImage alloc] initWithSize:NSMakeSize(surface->w, surface->h)]; 267 if (img == nil) { 268 return nil; 269 } 270 271 SDL_Surface **images = SDL_GetSurfaceImages(surface, NULL); 272 if (!images) { 273 return nil; 274 } 275 276 for (int i = 0; images[i]; ++i) { 277 SDL_Surface *converted = SDL_ConvertSurface(images[i], SDL_PIXELFORMAT_RGBA32); 278 if (!converted) { 279 SDL_free(images); 280 return nil; 281 } 282 283 // Premultiply the alpha channel 284 SDL_PremultiplySurfaceAlpha(converted, false); 285 286 NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL 287 pixelsWide:converted->w 288 pixelsHigh:converted->h 289 bitsPerSample:8 290 samplesPerPixel:4 291 hasAlpha:YES 292 isPlanar:NO 293 colorSpaceName:NSDeviceRGBColorSpace 294 bytesPerRow:converted->pitch 295 bitsPerPixel:SDL_BITSPERPIXEL(converted->format)]; 296 if (imgrep == nil) { 297 SDL_free(images); 298 SDL_DestroySurface(converted); 299 return nil; 300 } 301 302 // Copy the pixels 303 Uint8 *pixels = [imgrep bitmapData]; 304 SDL_memcpy(pixels, converted->pixels, (size_t)converted->h * converted->pitch); 305 SDL_DestroySurface(converted); 306 307 // Add the image representation 308 [img addRepresentation:imgrep]; 309 } 310 SDL_free(images); 311 312 return img; 313} 314 315/* 316 * macOS log support. 317 * 318 * This doesn't really have anything to do with the interfaces of the SDL video 319 * subsystem, but we need to stuff this into an Objective-C source code file. 320 * 321 * NOTE: This is copypasted in src/video/uikit/SDL_uikitvideo.m! Be sure both 322 * versions remain identical! 323 */ 324 325void SDL_NSLog(const char *prefix, const char *text) 326{ 327 @autoreleasepool { 328 NSString *nsText = [NSString stringWithUTF8String:text]; 329 if (prefix && *prefix) { 330 NSString *nsPrefix = [NSString stringWithUTF8String:prefix]; 331 NSLog(@"%@%@", nsPrefix, nsText); 332 } else { 333 NSLog(@"%@", nsText); 334 } 335 } 336} 337 338#endif // SDL_VIDEO_DRIVER_COCOA 339
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.