Atlas - SDL_qnxvideo.c

Home / ext / SDL / src / video / qnx Lines: 1 | Size: 20291 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 2026 BlackBerry Limited 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 22#include "SDL_internal.h" 23#include "../SDL_sysvideo.h" 24#include "../../events/SDL_keyboard_c.h" 25#include "../../events/SDL_mouse_c.h" 26#include "../../events/SDL_windowevents_c.h" 27#include "SDL_qnx.h" 28 29#include <errno.h> 30 31static screen_context_t context; 32static screen_event_t event; 33static bool video_initialized = false; 34 35screen_context_t * getContext() 36{ 37 return &context; 38} 39 40screen_event_t * getEvent() 41{ 42 return &event; 43} 44 45/** 46 * Initializes the QNX video plugin. 47 * Creates the Screen context and event handles used for all window operations 48 * by the plugin. 49 * @param SDL_VideoDevice *_this 50 * @return true if successful, false on error 51 */ 52static bool videoInit(SDL_VideoDevice *_this) 53{ 54 SDL_VideoDisplay display; 55 SDL_DisplayData *display_data; 56 SDL_DisplayMode display_mode; 57 SDL_DisplayModeData *display_mode_data; 58 59 int size[2]; 60 int index; 61 int display_count; 62 int active; 63 64 screen_display_t *screen_display; 65 66 if (video_initialized) { 67 return true; 68 } 69 70 if (screen_create_context(&context, 0) < 0) { 71 return false; 72 } 73 74 if (screen_create_event(&event) < 0) { 75 return false; 76 } 77 78 /* start with no displays and increment as attached displays are found */ 79 if (screen_get_context_property_iv(context, SCREEN_PROPERTY_DISPLAY_COUNT, &display_count) < 0) { 80 return false; 81 } 82 83 screen_display = SDL_calloc(display_count, sizeof(screen_display_t)); 84 if (screen_display == NULL) { 85 return false; 86 } 87 88 if (screen_get_context_property_pv(context, SCREEN_PROPERTY_DISPLAYS, (void **)screen_display) < 0) { 89 return false; 90 } 91 92 /* create SDL displays based on display info from the screen API */ 93 for (index = 0; index < display_count; index++) { 94 active = 0; 95 if (screen_get_display_property_iv(screen_display[index], SCREEN_PROPERTY_ATTACHED, &active) < 0) { 96 SDL_free(screen_display); 97 return false; 98 } 99 100 if (active) { 101 display_data = (SDL_DisplayData *)SDL_calloc(1, sizeof(SDL_DisplayData)); 102 if (display_data == NULL) { 103 SDL_free(screen_display); 104 return false; 105 } 106 SDL_zerop(display_data); 107 108 if (screen_get_display_property_iv(screen_display[index], SCREEN_PROPERTY_SIZE, size) < 0) { 109 SDL_free(screen_display); 110 SDL_free(display_data); 111 return false; 112 } 113 114 display_mode_data = (SDL_DisplayModeData *)SDL_calloc(1, sizeof(SDL_DisplayModeData)); 115 if (display_mode_data == NULL) { 116 SDL_free(screen_display); 117 SDL_free(display_data); 118 return false; 119 } 120 SDL_zerop(display_mode_data); 121 122 SDL_zero(display); 123 SDL_zero(display_mode); 124 125 display_data->screen_display = screen_display[index]; 126 display.internal = (void *)display_data; 127 128 display_mode.w = size[0]; 129 display_mode.h = size[1]; 130 display_mode.refresh_rate = 60; 131 display_mode.pixel_density = 1.0; 132 display_mode.internal = display_mode_data; 133 // This is assigned later when the window is created. For now, use a 134 // safe guess. 135 display_mode.format = SDL_PIXELFORMAT_RGBX8888; 136 display_mode_data->screen_format = SCREEN_FORMAT_RGBX8888; 137 // Be able to revert to the default display mode despite not having 138 // the actual object to refer to. 139 display_mode_data->screen_display_mode.index = SCREEN_DISPLAY_MODE_PREFERRED_INDEX; 140 141 // Added to current_mode when the display is added. 142 display.desktop_mode = display_mode; 143 144 if (!SDL_AddVideoDisplay(&display, false)) { 145 SDL_free(screen_display); 146 SDL_free(display_mode_data); 147 SDL_free(display_data); 148 return false; 149 } 150 } 151 } 152 153 initMouse(_this); 154 155 // Assume we have a mouse and keyboard 156 SDL_AddKeyboard(SDL_DEFAULT_KEYBOARD_ID, NULL); 157 SDL_AddMouse(SDL_DEFAULT_MOUSE_ID, NULL); 158 159 video_initialized = true; 160 161 SDL_free(screen_display); 162 163 return true; 164} 165 166static void videoQuit(SDL_VideoDevice *_this) 167{ 168 if (video_initialized) { 169 screen_destroy_event(event); 170 screen_destroy_context(context); 171 video_initialized = false; 172 } 173} 174 175/** 176 * Creates a new native Screen window and associates it with the given SDL 177 * window. 178 * @param SDL_VideoDevice *_this 179 * @param window SDL window to initialize 180 * @return true if successful, false on error 181 */ 182static bool createWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props) 183{ 184 SDL_WindowData *impl; 185 SDL_VideoDisplay *display = NULL; 186 SDL_DisplayData *display_data = NULL; 187 SDL_DisplayModeData *display_mode_data = NULL; 188 189 int size[2]; 190 int position[2]; 191 int numbufs; 192 int format; 193 int usage; 194 int has_focus_i; 195 196 impl = SDL_calloc(1, sizeof(*impl)); 197 if (!impl) { 198 return false; 199 } 200 window->internal = impl; 201 202 // Create a native window. 203 if (screen_create_window(&impl->window, context) < 0) { 204 goto fail; 205 } 206 207 // Set the native window's size to match the SDL window. 208 size[0] = window->w; 209 size[1] = window->h; 210 position[0] = window->x; 211 position[1] = window->y; 212 213 if (screen_set_window_property_iv(impl->window, SCREEN_PROPERTY_SIZE, 214 size) < 0) { 215 goto fail; 216 } 217 218 if (screen_set_window_property_iv(impl->window, SCREEN_PROPERTY_SOURCE_SIZE, 219 size) < 0) { 220 goto fail; 221 } 222 223 if (screen_set_window_property_iv(impl->window, SCREEN_PROPERTY_POSITION, 224 position) < 0) { 225 goto fail; 226 } 227 228 display = SDL_GetVideoDisplayForWindow(window); 229 SDL_assert(display != NULL); 230 SDL_assert(display->desktop_mode.internal != NULL); 231 display_mode_data = display->desktop_mode.internal; 232 233 if (screen_get_window_property_iv(impl->window, SCREEN_PROPERTY_FORMAT, 234 &format) < 0) { 235 format = display_mode_data->screen_format; 236 } 237 238 // Create window buffer(s). 239 if (window->flags & SDL_WINDOW_OPENGL) { 240 if (!glInitConfig(impl, &format)) { 241 goto fail; 242 } 243 numbufs = 2; 244 245 usage = SCREEN_USAGE_OPENGL_ES2 | SCREEN_USAGE_OPENGL_ES3; 246 if (screen_set_window_property_iv(impl->window, SCREEN_PROPERTY_USAGE, 247 &usage) < 0) { 248 goto fail; 249 } 250 } else { 251 numbufs = 1; 252 } 253 254 // We now know what the pixel format is, so we need to provide it to the 255 // right SDL APIs. 256 display->desktop_mode.format = screenToPixelFormat(format); 257 display_mode_data->screen_format = format; 258 259 display_data = display->internal; 260 // Initialized in videoInit() 261 SDL_assert(display_data != NULL); 262 263 // Set pixel format. 264 if (screen_set_window_property_iv(impl->window, SCREEN_PROPERTY_FORMAT, 265 &format) < 0) { 266 goto fail; 267 } 268 269 // Create buffer(s). 270 if (screen_create_window_buffers(impl->window, numbufs>0?numbufs:1) < 0) { 271 goto fail; 272 } 273 274 // Get initial focus state. Fallback to true. 275 if(screen_get_window_property_iv(impl->window, SCREEN_PROPERTY_FOCUS, &has_focus_i) < 0){ 276 impl->has_focus = true; 277 } else { 278 impl->has_focus = (bool)has_focus_i; 279 } 280 281 SDL_SetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_QNX_WINDOW_POINTER, impl->window); 282 283 return true; 284 285fail: 286 if (impl->window) { 287 screen_destroy_window(impl->window); 288 } 289 if (display_data) { 290 SDL_free(display_data); 291 display->internal = NULL; 292 } 293 294 SDL_free(impl); 295 window->internal = NULL; 296 return false; 297} 298 299/** 300 * Gets a pointer to the Screen buffer associated with the given window. Note 301 * that the buffer is actually created in createWindow(). 302 * @param SDL_VideoDevice *_this 303 * @param window SDL window to get the buffer for 304 * @param[out] pixels Holds a pointer to the window's buffer 305 * @param[out] format Holds the pixel format for the buffer 306 * @param[out] pitch Holds the number of bytes per line 307 * @return true if successful, false on error 308 */ 309static bool createWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window * window, SDL_PixelFormat * format, 310 void ** pixels, int *pitch) 311{ 312 int buffer_count; 313 SDL_WindowData *impl = (SDL_WindowData *)window->internal; 314 screen_buffer_t *buffer; 315 SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window); 316 317 if (screen_get_window_property_iv(impl->window, SCREEN_PROPERTY_BUFFER_COUNT, 318 &buffer_count) < 0) { 319 return false; 320 } 321 buffer = SDL_calloc(buffer_count, sizeof(screen_buffer_t)); 322 323 // Get a pointer to the buffer's memory. 324 if (screen_get_window_property_pv(impl->window, SCREEN_PROPERTY_BUFFERS, 325 (void **)buffer) < 0) { 326 return false; 327 } 328 329 if (screen_get_buffer_property_pv(*buffer, SCREEN_PROPERTY_POINTER, 330 pixels) < 0) { 331 return false; 332 } 333 334 // Set format and pitch. 335 if (screen_get_buffer_property_iv(*buffer, SCREEN_PROPERTY_STRIDE, 336 pitch) < 0) { 337 return false; 338 } 339 340 *format = display->desktop_mode.format; 341 return true; 342} 343 344/** 345 * Informs the window manager that the window needs to be updated. 346 * @param SDL_VideoDevice *_this 347 * @param window The window to update 348 * @param rects An array of reectangular areas to update 349 * @param numrects Rect array length 350 * @return true if successful, false on error 351 */ 352static bool updateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, const SDL_Rect *rects, 353 int numrects) 354{ 355 int buffer_count, *rects_int; 356 SDL_WindowData *impl = (SDL_WindowData *)window->internal; 357 screen_buffer_t *buffer; 358 359 if (screen_get_window_property_iv(impl->window, SCREEN_PROPERTY_BUFFER_COUNT, 360 &buffer_count) < 0) { 361 return false; 362 } 363 buffer = SDL_calloc(buffer_count, sizeof(screen_buffer_t)); 364 365 if (screen_get_window_property_pv(impl->window, SCREEN_PROPERTY_BUFFERS, 366 (void **)buffer) < 0) { 367 return false; 368 } 369 370 if(numrects>0){ 371 rects_int = SDL_calloc(4*numrects, sizeof(int)); 372 373 for(int i = 0; i < numrects; i++){ 374 rects_int[4*i] = rects[i].x; 375 rects_int[4*i+1] = rects[i].y; 376 rects_int[4*i+2] = rects[i].w; 377 rects_int[4*i+3] = rects[i].h; 378 } 379 380 if(screen_post_window(impl->window, buffer[0], numrects, rects_int, 0)) { 381 return false; 382 } 383 if(screen_flush_context(context, 0)) { 384 return false; 385 } 386 } 387 return true; 388} 389 390static SDL_FullscreenResult setWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_FullscreenOp fullscreen) 391{ 392 SDL_WindowData *window_data = window->internal; 393 SDL_DisplayData *display_data = display->internal; 394 int size[2] = { 0, 0 }; 395 int position[2] = { 0, 0 }; 396 397 if (!(window->flags & SDL_WINDOW_FULLSCREEN) && !fullscreen) { 398 return SDL_FULLSCREEN_SUCCEEDED; 399 } 400 401 if (fullscreen) { 402 SDL_Rect bounds; 403 404 if (!getDisplayBounds(_this, display, &bounds)) { 405 return SDL_FULLSCREEN_FAILED; 406 } 407 position[0] = bounds.x; 408 position[1] = bounds.y; 409 size[0] = bounds.w; 410 size[1] = bounds.h; 411 } else { 412 position[0] = window->x; 413 position[1] = window->y; 414 size[0] = window->w; 415 size[1] = window->h; 416 } 417 418 if (screen_set_window_property_iv(window_data->window, SCREEN_PROPERTY_SIZE, 419 size) < 0) { 420 return SDL_FULLSCREEN_FAILED; 421 } 422 423 if (screen_set_window_property_iv(window_data->window, SCREEN_PROPERTY_SOURCE_SIZE, 424 size) < 0) { 425 return SDL_FULLSCREEN_FAILED; 426 } 427 428 if (screen_set_window_property_iv(window_data->window, SCREEN_PROPERTY_POSITION, 429 position) < 0) { 430 return SDL_FULLSCREEN_FAILED; 431 } 432 433 SDL_SendWindowEvent(window, fullscreen ? SDL_EVENT_WINDOW_ENTER_FULLSCREEN : SDL_EVENT_WINDOW_LEAVE_FULLSCREEN, 0, 0); 434 435 return SDL_FULLSCREEN_SUCCEEDED; 436} 437 438static SDL_DisplayID getDisplayForWindow(SDL_VideoDevice *_this, SDL_Window *window) 439{ 440 // We need this, otherwise SDL will fallback to the primary display, meaning 441 // any data we store about the display will be inconveniently overwritten. 442 SDL_WindowData *impl = (SDL_WindowData *)window->internal; 443 SDL_DisplayData *display_data; 444 445 screen_display_t screen_display; 446 447 if (impl == NULL) { 448 return 0; 449 } 450 451 if (screen_get_window_property_pv(impl->window, SCREEN_PROPERTY_DISPLAY, 452 (void **)&screen_display) < 0) { 453 return 0; 454 } 455 456 for (int i = 0; i < _this->num_displays; i++) { 457 display_data = _this->displays[i]->internal; 458 if (display_data && (display_data->screen_display == screen_display)) { 459 return _this->displays[i]->id; 460 } 461 } 462 463 return 0; 464} 465 466/** 467 * Runs the main event loop. 468 * @param SDL_VideoDevice *_this 469 */ 470static void pumpEvents(SDL_VideoDevice *_this) 471{ 472 SDL_Window *window; 473 SDL_WindowData *impl; 474 int type; 475 int has_focus_i; 476 bool has_focus; 477 478 // Let apps know the state of focus. 479 for (window = _this->windows; window; window = window->next) { 480 impl = (SDL_WindowData *)window->internal; 481 if (screen_get_window_property_iv(impl->window, SCREEN_PROPERTY_FOCUS, &has_focus_i) < 0){ 482 continue; 483 } 484 has_focus = (bool)has_focus_i; 485 486 if (impl->has_focus != has_focus) { 487 SDL_SendWindowEvent(window, (has_focus ? SDL_EVENT_WINDOW_FOCUS_GAINED : SDL_EVENT_WINDOW_FOCUS_LOST), 0, 0); 488 SDL_SendWindowEvent(window, (has_focus ? SDL_EVENT_WINDOW_MOUSE_ENTER : SDL_EVENT_WINDOW_MOUSE_LEAVE), 0, 0); 489 // Update the SDL mouse to track the window it's focused on. 490 SDL_SetMouseFocus(window); 491 SDL_SetKeyboardFocus(window); 492 } 493 } 494 495 for (;;) { 496 if (screen_get_event(context, event, 0) < 0) { 497 break; 498 } 499 500 if (screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type) 501 < 0) { 502 break; 503 } 504 505 if (type == SCREEN_EVENT_NONE) { 506 break; 507 } 508 509 switch (type) { 510 case SCREEN_EVENT_KEYBOARD: 511 handleKeyboardEvent(event); 512 break; 513 514 case SCREEN_EVENT_POINTER: 515 handlePointerEvent(event); 516 break; 517 518 default: 519 break; 520 } 521 } 522} 523 524/** 525 * Updates the size of the native window using the geometry of the SDL window. 526 * @param SDL_VideoDevice *_this 527 * @param window SDL window to update 528 */ 529static void setWindowSize(SDL_VideoDevice *_this, SDL_Window *window) 530{ 531 SDL_WindowData *impl = (SDL_WindowData *)window->internal; 532 int size[2]; 533 534 size[0] = window->pending.w; 535 size[1] = window->pending.h; 536 537 if (!(window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_MAXIMIZED))) { 538 if (screen_destroy_window_buffers(impl->window) < 0) { 539 return; 540 } 541 impl->resize = 1; 542 543 screen_set_window_property_iv(impl->window, SCREEN_PROPERTY_SIZE, size); 544 screen_set_window_property_iv(impl->window, SCREEN_PROPERTY_SOURCE_SIZE, size); 545 546 screen_create_window_buffers(impl->window, (window->flags & SDL_WINDOW_OPENGL) ? 2 : 1); 547 } else { 548 window->last_size_pending = false; 549 } 550} 551 552/** 553 * Makes the native window associated with the given SDL window visible. 554 * @param SDL_VideoDevice *_this 555 * @param window SDL window to update 556 */ 557static void showWindow(SDL_VideoDevice *_this, SDL_Window *window) 558{ 559 SDL_WindowData *impl = (SDL_WindowData *)window->internal; 560 const int visible = 1; 561 562 screen_set_window_property_iv(impl->window, SCREEN_PROPERTY_VISIBLE, 563 &visible); 564} 565 566/** 567 * Makes the native window associated with the given SDL window invisible. 568 * @param SDL_VideoDevice *_this 569 * @param window SDL window to update 570 */ 571static void hideWindow(SDL_VideoDevice *_this, SDL_Window *window) 572{ 573 SDL_WindowData *impl = (SDL_WindowData *)window->internal; 574 const int visible = 0; 575 576 screen_set_window_property_iv(impl->window, SCREEN_PROPERTY_VISIBLE, 577 &visible); 578} 579 580/** 581 * Destroys the native window associated with the given SDL window. 582 * @param SDL_VideoDevice *_this 583 * @param window SDL window that is being destroyed 584 */ 585static void destroyWindow(SDL_VideoDevice *_this, SDL_Window *window) 586{ 587 SDL_WindowData *impl = (SDL_WindowData *)window->internal; 588 589 if (impl) { 590 screen_destroy_window(impl->window); 591 window->internal = NULL; 592 } 593} 594 595/** 596 * Frees the plugin object created by createDevice(). 597 * @param device Plugin object to free 598 */ 599static void deleteDevice(SDL_VideoDevice *device) 600{ 601 SDL_free(device); 602} 603 604/** 605 * Creates the QNX video plugin used by SDL. 606 * @return Initialized device if successful, NULL otherwise 607 */ 608static SDL_VideoDevice *createDevice(void) 609{ 610 SDL_VideoDevice *device; 611 612 device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice)); 613 if (!device) { 614 return NULL; 615 } 616 617 device->internal = NULL; 618 device->VideoInit = videoInit; 619 device->VideoQuit = videoQuit; 620 device->CreateSDLWindow = createWindow; 621 device->CreateWindowFramebuffer = createWindowFramebuffer; 622 device->UpdateWindowFramebuffer = updateWindowFramebuffer; 623 device->SetWindowSize = setWindowSize; 624 device->SetWindowFullscreen = setWindowFullscreen; 625 device->ShowWindow = showWindow; 626 device->HideWindow = hideWindow; 627 device->GetDisplayForWindow = getDisplayForWindow; 628 device->GetDisplayBounds = getDisplayBounds; 629 device->GetDisplayModes = getDisplayModes; 630#if 0 631 device->SetDisplayMode = setDisplayMode; 632#endif 633 device->PumpEvents = pumpEvents; 634 device->DestroyWindow = destroyWindow; 635 636 device->GL_LoadLibrary = glLoadLibrary; 637 device->GL_GetProcAddress = glGetProcAddress; 638 device->GL_CreateContext = glCreateContext; 639 device->GL_SetSwapInterval = glSetSwapInterval; 640 device->GL_SwapWindow = glSwapWindow; 641 device->GL_MakeCurrent = glMakeCurrent; 642 device->GL_DestroyContext = glDeleteContext; 643 device->GL_UnloadLibrary = glUnloadLibrary; 644 645 device->free = deleteDevice; 646 647 return device; 648} 649 650VideoBootStrap QNX_bootstrap = { 651 "qnx", "QNX Screen", 652 createDevice, 653 NULL, // no ShowMessageBox implementation 654 false 655}; 656
[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.