From 68a4bb01e0d549bfa1f2418dd9463f62980eb210 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 1 Aug 2023 18:48:35 -0700 Subject: [PATCH] Allocate displays as an array of pointers instead of an array of objects This fixes current_mode from pointing at the wrong data when displays are moved around --- src/video/SDL_sysvideo.h | 2 +- src/video/SDL_video.c | 119 ++++++++++++-------------- src/video/android/SDL_androidvideo.c | 2 +- src/video/cocoa/SDL_cocoaevents.m | 2 +- src/video/cocoa/SDL_cocoamodes.m | 2 +- src/video/cocoa/SDL_cocoawindow.m | 4 +- src/video/n3ds/SDL_n3dsvideo.c | 1 - src/video/uikit/SDL_uikitmodes.m | 2 +- src/video/wayland/SDL_waylandvideo.c | 2 +- src/video/wayland/SDL_waylandwindow.c | 2 +- src/video/windows/SDL_windowsmodes.c | 18 ++-- src/video/x11/SDL_x11messagebox.c | 4 +- src/video/x11/SDL_x11modes.c | 2 +- src/video/x11/SDL_x11video.c | 2 +- 14 files changed, 79 insertions(+), 85 deletions(-) diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index d4eedd2a6..034d802b0 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -363,7 +363,7 @@ struct SDL_VideoDevice SDL_Window *wakeup_window; SDL_Mutex *wakeup_lock; /* Initialized only if WaitEventTimeout/SendWakeupEvent are supported */ int num_displays; - SDL_VideoDisplay *displays; + SDL_VideoDisplay **displays; SDL_Window *windows; SDL_Window *grabbed_window; Uint8 window_magic; diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 7cfe08da0..f3637f1ce 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -642,57 +642,51 @@ SDL_DisplayID SDL_AddBasicVideoDisplay(const SDL_DisplayMode *desktop_mode) SDL_DisplayID SDL_AddVideoDisplay(const SDL_VideoDisplay *display, SDL_bool send_event) { - SDL_VideoDisplay *displays, *new_display; - SDL_DisplayID id = 0; + SDL_VideoDisplay **displays, *new_display; + SDL_DisplayID id; + int i; - displays = (SDL_VideoDisplay *)SDL_malloc((_this->num_displays + 1) * sizeof(*displays)); - if (displays) { - int i; - - if (_this->displays) { - /* The display list may contain self-referential pointers to the desktop mode. */ - SDL_memcpy(displays, _this->displays, _this->num_displays * sizeof(*displays)); - for (i = 0; i < _this->num_displays; ++i) { - if (displays[i].current_mode == &_this->displays[i].desktop_mode) { - displays[i].current_mode = &displays[i].desktop_mode; - } - } - - SDL_free(_this->displays); - } - - _this->displays = displays; - id = _this->next_object_id++; - new_display = &displays[_this->num_displays++]; - - SDL_memcpy(new_display, display, sizeof(*new_display)); - new_display->id = id; - new_display->device = _this; - if (display->name) { - new_display->name = SDL_strdup(display->name); - } else { - char name[32]; - - SDL_itoa(id, name, 10); - new_display->name = SDL_strdup(name); - } - if (new_display->content_scale == 0.0f) { - new_display->content_scale = 1.0f; - } - - new_display->desktop_mode.displayID = id; - new_display->current_mode = &new_display->desktop_mode; - SDL_FinalizeDisplayMode(&new_display->desktop_mode); - - for (i = 0; i < new_display->num_fullscreen_modes; ++i) { - new_display->fullscreen_modes[i].displayID = id; - } - - if (send_event) { - SDL_SendDisplayEvent(new_display, SDL_EVENT_DISPLAY_CONNECTED, 0); - } - } else { + new_display = (SDL_VideoDisplay *)SDL_malloc(sizeof(*new_display)); + if (!new_display) { SDL_OutOfMemory(); + return 0; + } + + displays = (SDL_VideoDisplay **)SDL_realloc(_this->displays, (_this->num_displays + 1) * sizeof(*displays)); + if (!displays) { + SDL_OutOfMemory(); + SDL_free(new_display); + return 0; + } + _this->displays = displays; + _this->displays[_this->num_displays++] = new_display; + + id = _this->next_object_id++; + SDL_memcpy(new_display, display, sizeof(*new_display)); + new_display->id = id; + new_display->device = _this; + if (display->name) { + new_display->name = SDL_strdup(display->name); + } else { + char name[32]; + + SDL_itoa(id, name, 10); + new_display->name = SDL_strdup(name); + } + if (new_display->content_scale == 0.0f) { + new_display->content_scale = 1.0f; + } + + new_display->desktop_mode.displayID = id; + new_display->current_mode = &new_display->desktop_mode; + SDL_FinalizeDisplayMode(&new_display->desktop_mode); + + for (i = 0; i < new_display->num_fullscreen_modes; ++i) { + new_display->fullscreen_modes[i].displayID = id; + } + + if (send_event) { + SDL_SendDisplayEvent(new_display, SDL_EVENT_DISPLAY_CONNECTED, 0); } return id; } @@ -715,7 +709,7 @@ void SDL_DelVideoDisplay(SDL_DisplayID displayID, SDL_bool send_event) return; } - display = &_this->displays[display_index]; + display = _this->displays[display_index]; if (send_event) { SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_DISCONNECTED, 0); @@ -727,6 +721,7 @@ void SDL_DelVideoDisplay(SDL_DisplayID displayID, SDL_bool send_event) display->desktop_mode.driverdata = NULL; SDL_free(display->driverdata); display->driverdata = NULL; + SDL_free(display); if (display_index < (_this->num_displays - 1)) { SDL_memmove(&_this->displays[display_index], &_this->displays[display_index + 1], (_this->num_displays - display_index - 1) * sizeof(_this->displays[display_index])); @@ -755,7 +750,7 @@ SDL_DisplayID *SDL_GetDisplays(int *count) } for (i = 0; i < _this->num_displays; ++i) { - displays[i] = _this->displays[i].id; + displays[i] = _this->displays[i]->id; } displays[i] = 0; } else { @@ -776,7 +771,7 @@ SDL_VideoDisplay *SDL_GetVideoDisplay(SDL_DisplayID displayID) if (display_index < 0) { return NULL; } - return &_this->displays[display_index]; + return _this->displays[display_index]; } SDL_VideoDisplay *SDL_GetVideoDisplayForWindow(SDL_Window *window) @@ -790,7 +785,7 @@ SDL_DisplayID SDL_GetPrimaryDisplay(void) SDL_UninitializedVideo(); return 0; } - return _this->displays[0].id; + return _this->displays[0]->id; } int SDL_GetDisplayIndex(SDL_DisplayID displayID) @@ -802,7 +797,7 @@ int SDL_GetDisplayIndex(SDL_DisplayID displayID) } for (display_index = 0; display_index < _this->num_displays; ++display_index) { - if (displayID == _this->displays[display_index].id) { + if (displayID == _this->displays[display_index]->id) { return display_index; } } @@ -853,7 +848,7 @@ int SDL_GetDisplayBounds(SDL_DisplayID displayID, SDL_Rect *rect) rect->x = 0; rect->y = 0; } else { - SDL_GetDisplayBounds(_this->displays[SDL_GetDisplayIndex(displayID) - 1].id, rect); + SDL_GetDisplayBounds(_this->displays[SDL_GetDisplayIndex(displayID) - 1]->id, rect); rect->x += rect->w; } rect->w = display->current_mode->w; @@ -1256,7 +1251,7 @@ static SDL_DisplayID GetDisplayForRect(int x, int y, int w, int h) if (_this) { for (i = 0; i < _this->num_displays; ++i) { - SDL_VideoDisplay *display = &_this->displays[i]; + SDL_VideoDisplay *display = _this->displays[i]; SDL_Rect display_rect; SDL_GetDisplayBounds(display->id, &display_rect); @@ -1390,14 +1385,14 @@ static void SDL_CheckWindowDisplayChanged(SDL_Window *window) /* Sanity check our fullscreen windows */ display_index = SDL_GetDisplayIndex(displayID); for (i = 0; i < _this->num_displays; ++i) { - SDL_VideoDisplay *display = &_this->displays[i]; + SDL_VideoDisplay *display = _this->displays[i]; if (display->fullscreen_window == window) { if (display_index != i) { if (display_index < 0) { display_index = i; } else { - SDL_VideoDisplay *new_display = &_this->displays[display_index]; + SDL_VideoDisplay *new_display = _this->displays[display_index]; /* The window was moved to a different display */ if (new_display->fullscreen_window && @@ -1489,7 +1484,7 @@ static int SDL_UpdateFullscreenMode(SDL_Window *window, SDL_bool fullscreen) } } else { for (i = 0; i < _this->num_displays; ++i) { - display = &_this->displays[i]; + display = _this->displays[i]; if (display->fullscreen_window == window) { break; } @@ -1528,7 +1523,7 @@ static int SDL_UpdateFullscreenMode(SDL_Window *window, SDL_bool fullscreen) } } else if (fullscreen && window->last_fullscreen_exclusive_display && !window->fullscreen_exclusive) { for (i = 0; i < _this->num_displays; ++i) { - SDL_VideoDisplay *last_display = &_this->displays[i]; + SDL_VideoDisplay *last_display = _this->displays[i]; if (last_display->fullscreen_window == window) { SDL_SetDisplayModeForDisplay(last_display, NULL); if (_this->SetWindowFullscreen) { @@ -1584,7 +1579,7 @@ static int SDL_UpdateFullscreenMode(SDL_Window *window, SDL_bool fullscreen) /* Restore the video mode on other displays if needed */ for (i = 0; i < _this->num_displays; ++i) { - SDL_VideoDisplay *other = &_this->displays[i]; + SDL_VideoDisplay *other = _this->displays[i]; if (other != display && other->fullscreen_window == window) { SDL_SetDisplayModeForDisplay(other, NULL); if (_this->SetWindowFullscreen) { @@ -3733,7 +3728,7 @@ void SDL_VideoQuit(void) _this->VideoQuit(_this); for (i = _this->num_displays; i--; ) { - SDL_VideoDisplay *display = &_this->displays[i]; + SDL_VideoDisplay *display = _this->displays[i]; SDL_DelVideoDisplay(display->id, SDL_FALSE); } if (_this->displays) { diff --git a/src/video/android/SDL_androidvideo.c b/src/video/android/SDL_androidvideo.c index 021607ce5..ede5b1c96 100644 --- a/src/video/android/SDL_androidvideo.c +++ b/src/video/android/SDL_androidvideo.c @@ -268,7 +268,7 @@ void Android_SendResize(SDL_Window *window) */ SDL_VideoDevice *device = SDL_GetVideoDevice(); if (device && device->num_displays > 0) { - SDL_VideoDisplay *display = &device->displays[0]; + SDL_VideoDisplay *display = device->displays[0]; SDL_DisplayMode desktop_mode; SDL_zero(desktop_mode); diff --git a/src/video/cocoa/SDL_cocoaevents.m b/src/video/cocoa/SDL_cocoaevents.m index 5e0c3e49c..221a61d91 100644 --- a/src/video/cocoa/SDL_cocoaevents.m +++ b/src/video/cocoa/SDL_cocoaevents.m @@ -255,7 +255,7 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent) SDL_Window *window = device->windows; int i; for (i = 0; i < device->num_displays; ++i) { - SDL_Window *fullscreen_window = device->displays[i].fullscreen_window; + SDL_Window *fullscreen_window = device->displays[i]->fullscreen_window; if (fullscreen_window) { if (fullscreen_window->flags & SDL_WINDOW_MINIMIZED) { SDL_RestoreWindow(fullscreen_window); diff --git a/src/video/cocoa/SDL_cocoamodes.m b/src/video/cocoa/SDL_cocoamodes.m index e6b90b85a..34e9c2d5b 100644 --- a/src/video/cocoa/SDL_cocoamodes.m +++ b/src/video/cocoa/SDL_cocoamodes.m @@ -520,7 +520,7 @@ void Cocoa_QuitModes(SDL_VideoDevice *_this) int i, j; for (i = 0; i < _this->num_displays; ++i) { - SDL_VideoDisplay *display = &_this->displays[i]; + SDL_VideoDisplay *display = _this->displays[i]; SDL_DisplayModeData *mode; if (display->current_mode->driverdata != display->desktop_mode.driverdata) { diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 3bdcb22eb..10071cdf0 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -2467,9 +2467,9 @@ SDL_DisplayID Cocoa_GetDisplayForWindow(SDL_VideoDevice *_this, SDL_Window *wind displayid = [[screen.deviceDescription objectForKey:@"NSScreenNumber"] unsignedIntValue]; for (i = 0; i < _this->num_displays; i++) { - SDL_DisplayData *displaydata = _this->displays[i].driverdata; + SDL_DisplayData *displaydata = _this->displays[i]->driverdata; if (displaydata != NULL && displaydata->display == displayid) { - return _this->displays[i].id; + return _this->displays[i]->id; } } } diff --git a/src/video/n3ds/SDL_n3dsvideo.c b/src/video/n3ds/SDL_n3dsvideo.c index eb669fe09..74b52071a 100644 --- a/src/video/n3ds/SDL_n3dsvideo.c +++ b/src/video/n3ds/SDL_n3dsvideo.c @@ -48,7 +48,6 @@ struct SDL_DisplayData static void N3DS_DeleteDevice(SDL_VideoDevice *device) { - SDL_free(device->displays); SDL_free(device->driverdata); SDL_free(device); } diff --git a/src/video/uikit/SDL_uikitmodes.m b/src/video/uikit/SDL_uikitmodes.m index 06141034c..bc13c0df8 100644 --- a/src/video/uikit/SDL_uikitmodes.m +++ b/src/video/uikit/SDL_uikitmodes.m @@ -392,7 +392,7 @@ void UIKit_QuitModes(SDL_VideoDevice *_this) int i, j; @autoreleasepool { for (i = 0; i < _this->num_displays; i++) { - SDL_VideoDisplay *display = &_this->displays[i]; + SDL_VideoDisplay *display = _this->displays[i]; UIKit_FreeDisplayModeData(&display->desktop_mode); for (j = 0; j < display->num_fullscreen_modes; j++) { diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index 2cd4495e4..cec877530 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -935,7 +935,7 @@ static void Wayland_VideoCleanup(SDL_VideoDevice *_this) Wayland_FiniMouse(data); for (i = _this->num_displays - 1; i >= 0; --i) { - SDL_VideoDisplay *display = &_this->displays[i]; + SDL_VideoDisplay *display = _this->displays[i]; Wayland_free_display(display); } diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 58650e651..442224f21 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -2154,7 +2154,7 @@ int Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window) if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) { int i; for (i = 0; i < _this->num_displays; i++) { - float scale = _this->displays[i].driverdata->scale_factor; + float scale = _this->displays[i]->driverdata->scale_factor; data->windowed_scale_factor = SDL_max(data->windowed_scale_factor, scale); } } diff --git a/src/video/windows/SDL_windowsmodes.c b/src/video/windows/SDL_windowsmodes.c index 5868e9a5e..df80ba3f6 100644 --- a/src/video/windows/SDL_windowsmodes.c +++ b/src/video/windows/SDL_windowsmodes.c @@ -352,7 +352,7 @@ static void WIN_AddDisplay(SDL_VideoDevice *_this, HMONITOR hMonitor, const MONI // ready to be added to allow any displays that we can't fully query to be // removed for (i = 0; i < _this->num_displays; ++i) { - SDL_DisplayData *driverdata = _this->displays[i].driverdata; + SDL_DisplayData *driverdata = _this->displays[i]->driverdata; if (SDL_wcscmp(driverdata->DeviceName, info->szDevice) == 0) { SDL_bool moved = (index != i); SDL_bool changed_bounds = SDL_FALSE; @@ -368,11 +368,11 @@ static void WIN_AddDisplay(SDL_VideoDevice *_this, HMONITOR hMonitor, const MONI } if (moved) { - SDL_VideoDisplay tmp; + SDL_VideoDisplay *tmp; - SDL_memcpy(&tmp, &_this->displays[index], sizeof(tmp)); - SDL_memcpy(&_this->displays[index], &_this->displays[i], sizeof(tmp)); - SDL_memcpy(&_this->displays[i], &tmp, sizeof(tmp)); + tmp = _this->displays[index]; + _this->displays[index] = _this->displays[i]; + _this->displays[i] = tmp; i = index; } @@ -380,7 +380,7 @@ static void WIN_AddDisplay(SDL_VideoDevice *_this, HMONITOR hMonitor, const MONI driverdata->state = DisplayUnchanged; if (!_this->setting_display_mode) { - SDL_VideoDisplay *existing_display = &_this->displays[i]; + SDL_VideoDisplay *existing_display = _this->displays[i]; SDL_Rect bounds; SDL_ResetFullscreenDisplayModes(existing_display); @@ -654,7 +654,7 @@ void WIN_RefreshDisplays(SDL_VideoDevice *_this) // Mark all displays as potentially invalid to detect // entries that have actually been removed for (i = 0; i < _this->num_displays; ++i) { - SDL_DisplayData *driverdata = _this->displays[i].driverdata; + SDL_DisplayData *driverdata = _this->displays[i]->driverdata; driverdata->state = DisplayRemoved; } @@ -665,7 +665,7 @@ void WIN_RefreshDisplays(SDL_VideoDevice *_this) // Delete any entries still marked as invalid, iterate // in reverse as each delete takes effect immediately for (i = _this->num_displays - 1; i >= 0; --i) { - SDL_VideoDisplay *display = &_this->displays[i]; + SDL_VideoDisplay *display = _this->displays[i]; SDL_DisplayData *driverdata = display->driverdata; if (driverdata->state == DisplayRemoved) { SDL_DelVideoDisplay(display->id, SDL_TRUE); @@ -674,7 +674,7 @@ void WIN_RefreshDisplays(SDL_VideoDevice *_this) // Send events for any newly added displays for (i = 0; i < _this->num_displays; ++i) { - SDL_VideoDisplay *display = &_this->displays[i]; + SDL_VideoDisplay *display = _this->displays[i]; SDL_DisplayData *driverdata = display->driverdata; if (driverdata->state == DisplayAdded) { SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_CONNECTED, 0); diff --git a/src/video/x11/SDL_x11messagebox.c b/src/video/x11/SDL_x11messagebox.c index d2ce6640d..cc197227e 100644 --- a/src/video/x11/SDL_x11messagebox.c +++ b/src/video/x11/SDL_x11messagebox.c @@ -467,8 +467,8 @@ static int X11_MessageBoxCreateWindow(SDL_MessageBoxDataX11 *data) X11_XTranslateCoordinates(display, windowdata->xwindow, RootWindow(display, data->screen), x, y, &x, &y, &dummy); } else { const SDL_VideoDevice *dev = SDL_GetVideoDevice(); - if ((dev) && (dev->displays) && (dev->num_displays > 0)) { - const SDL_VideoDisplay *dpy = &dev->displays[0]; + if (dev && dev->displays && dev->num_displays > 0) { + const SDL_VideoDisplay *dpy = dev->displays[0]; const SDL_DisplayData *dpydata = dpy->driverdata; x = dpydata->x + ((dpy->current_mode->w - data->dialog_width) / 2); y = dpydata->y + ((dpy->current_mode->h - data->dialog_height) / 3); diff --git a/src/video/x11/SDL_x11modes.c b/src/video/x11/SDL_x11modes.c index 5bf237272..e8c0ad331 100644 --- a/src/video/x11/SDL_x11modes.c +++ b/src/video/x11/SDL_x11modes.c @@ -99,7 +99,7 @@ static void UpdateDisplayContentScale(float scale) if (viddevice) { for (i = 0; i < viddevice->num_displays; ++i) { - SDL_SetDisplayContentScale(&viddevice->displays[i], scale); + SDL_SetDisplayContentScale(viddevice->displays[i], scale); } } } diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c index 1016a7abe..8b14e55c4 100644 --- a/src/video/x11/SDL_x11video.c +++ b/src/video/x11/SDL_x11video.c @@ -84,7 +84,7 @@ static int X11_SafetyNetErrHandler(Display *d, XErrorEvent *e) if (device != NULL) { int i; for (i = 0; i < device->num_displays; i++) { - SDL_VideoDisplay *display = &device->displays[i]; + SDL_VideoDisplay *display = device->displays[i]; if (SDL_GetCurrentDisplayMode(display->id) != SDL_GetDesktopDisplayMode(display->id)) { X11_SetDisplayMode(device, display, &display->desktop_mode); }