SDL2: How to keep aspect ratio when resizing the window
c++, linux, sdl, sdl-2
Solution
Some window managers seems to ignore resize requests made while WM itself resizes window (e.g. while mouse button held). On contrary, `SDL_GetWindowSize` returns cached values, which in that specific case sometimes happens to be wrong.
I see no platform-independent way to achieve that, other than constantly calling `SDL_SetWindowSize` on each frame, just in case. It could be achieved using platform-specific APIs, though (like `SDL_GetWindowSysWMInfo` and then using Xlib).
Problem
I am trying to create a SDL window which keeps its aspect ratio when resize event happens. If user widens the window, the height is increased and vice versa. I catch the SDL_WINDOWEVENT_RESIZED event, calculate new width or height which maintains the aspect ratio and then call SDL_SetWindowSize() with calculated values. The problem is that calling the SDL_SetWindowSize() function inside the event polling loop does nothing on the screen. SDL does update the window size variables (calling SDL_GetWindowSize() in my main loop returns the updated window dimensions). However, the actual window is not updated. The only way I can get this to work is to call constantly SDL_SetWindowSize() in the main loop, but I think that is the wrong way of doing things. The code below illustrates my problem. Is there a better and cleaner way to get this to work? I am using SDL 2.0.3 and 64-bit Ubuntu Linux with GNOME desktop. ``` #include <SDL2/SDL.h> static const float ASPECT_RATIO = 16.f/9.f; SDL_Window* window; SDL_Renderer* renderer; uint32_t windowID; SDL_Rect screen; bool done = false; bool resizeDone = false; void handle_events() { SDL_Event e; while (SDL_PollEvent(&e)) { switch (e.type) { case SDL_WINDOWEVENT: if(e.window.windowID == windowID) { switch(e.window.event) { case SDL_WINDOWEVENT_RESIZED: { int width = e.window.data1; int height = e.window.data2; float aspectRatio = (float)width/(float)height; if(aspectRatio != ASPECT_RATIO) { if(aspectRatio > ASPECT_RATIO) { height = (1.f / ASPECT_RATIO) * width; } else { width = ASPECT_RATIO * height; } printf("Setting window size to %d, %d, aspect ratio: %f\n", width, height, (float)width/(float)height); } screen.w = width; screen.h = height; SDL_SetWindowSize(window, width, height); // <-- does not work resizeDone = true; break; } } } break; case SDL_QUIT: done = true; break; default: break; } } } void run() { while(!done) { //SDL_SetWindowSize(window, screen.w, screen.h); // <-- works handle_events(); SDL_RenderClear(renderer); SDL_RenderPresent(renderer); if(resizeDone) { int w, h; SDL_GetWindowSize(window, &w, &h); printf("SDL_GetWindowSize: %d, %d\n", w, h); resizeDone = false; } } } int main(int, char**) { SDL_Init(SDL_INIT_VIDEO); uint32_t window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE; window = SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); windowID = SDL_GetWindowID(window); renderer = SDL_CreateRenderer(window, -1, 0); SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); run(); SDL_Quit(); return 0; } ```