From 94e20cdff54ffac9252aced1d60c9e7b70b2d34f Mon Sep 17 00:00:00 2001 From: igor Date: Thu, 28 May 2026 20:09:50 -0700 Subject: [PATCH] Fixed window positioning on Windows. TODO: Test again on Linux and MacOS. --- sdl_handmade.c | 68 ++++++++++++++++++++++++++++++++++++++------------ sdl_handmade.h | 7 ++++++ 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/sdl_handmade.c b/sdl_handmade.c index 28d43f1..aba61cb 100644 --- a/sdl_handmade.c +++ b/sdl_handmade.c @@ -138,27 +138,56 @@ void DEBUGPlatformFreeFileMemory(thread_context *Thread, void *Memory) free(Memory); // TODO: Should we accept debug_read_file_result instead of just memory. } -static sdl_window_size SDLGetWindowSize(SDL_Window *Window) +static sdl_border_size SDLGetWindowBorderSizes(SDL_Window *Window) { + sdl_border_size Result; + SDL_GetWindowBordersSize(Window, &Result.Top, &Result.Left, &Result.Bottom, &Result.Right); + return Result; +} + +// NOTE: All SDL window functions (SDL_GetWindowSize, SDL_GetWindowPosition, SDL_SetWindowPosition, SDL_SetWindowSize) +// work ONLY with client area. This has some weird behavior with SDL_SetWindowPosition where SDLGetWindowBorderSizes +// reports left border (of 8 in our case), however it does not have that border in reality, so we ignore left and right borders. +// As a result, we ignore left and right borders, for now. +static sdl_window_size SDLGetBorderedWindowSize(SDL_Window *Window) +{ + sdl_border_size Border = SDLGetWindowBorderSizes(Window); + sdl_window_size Dimension; SDL_GetWindowSize(Window, &Dimension.Width, &Dimension.Height); + Dimension.Height += Border.Top + Border.Bottom; + // Dimension.Width += Border.Left + Border.Right; + return Dimension; } -static sdl_window_position SDLGetWindowPosition(SDL_Window *Window) +static sdl_window_position SDLGetBorderedWindowPosition(SDL_Window *Window) { - // NOTE: SDL_GetWindowPosition returns the client area position. - S32 top, left; - SDL_GetWindowBordersSize(Window, &top, &left, 0, 0); + sdl_border_size Border = SDLGetWindowBorderSizes(Window); sdl_window_position Position; SDL_GetWindowPosition(Window, &Position.X, &Position.Y); - Position.X -= left; - Position.Y -= top; + // Position.X -= Border.Left; + Position.Y -= Border.Top; return Position; } +static void SDLSetBorderedWindowPosition(SDL_Window *Window, S32 X, S32 Y) +{ + sdl_border_size Border = SDLGetWindowBorderSizes(Window); + + SDL_SetWindowPosition(Window, X, Y + Border.Top); +} + +static void SDLSetBorderedWindowSize(SDL_Window *Window, S32 Width, S32 Height) +{ + sdl_border_size Border = SDLGetWindowBorderSizes(Window); + + // SDL_SetWindowSize(Window, Width - (Border.Left + Border.Right), Height - (Border.Top + Border.Bottom)); + SDL_SetWindowSize(Window, Width, Height - (Border.Top + Border.Bottom)); +} + static void SDLResizeTexture(offscreen_buffer *Buffer, SDL_Renderer *Renderer, int Width, int Height) { if(Buffer->Texture) @@ -191,7 +220,7 @@ static void SDLDisplayBufferInWindow(offscreen_buffer *Buffer, SDL_Window *Windo /* TODO: We temporarily introduce the target rectangle to avoid stretching the canvas. */ /* SDL_RenderCopy(Renderer, Buffer.Texture, 0, 0); */ - sdl_window_size WinSize = SDLGetWindowSize(Window); + sdl_window_size WinSize = SDLGetBorderedWindowSize(Window); if(WinSize.Width >= Buffer->Width*2 && WinSize.Height >= Buffer->Height*2) { SDL_Rect dest_rect = { OffsetX, OffsetY, Buffer->Width*2, Buffer->Height*2 }; SDL_RenderCopy(Renderer, Buffer->Texture, 0, (const SDL_Rect *)(&dest_rect)); @@ -315,16 +344,16 @@ static void SDLToggleFullscreen(SDL_Window *Window) { if(IsFullscreen) { if(SDL_SetWindowFullscreen(Window, 0) == 0) { - SDL_SetWindowSize(Window, WindowSize.Width, WindowSize.Height); - SDL_SetWindowPosition(Window, WindowPosition.X, WindowPosition.Y); + SDLSetBorderedWindowSize(Window, WindowSize.Width, WindowSize.Height); + SDLSetBorderedWindowPosition(Window, WindowPosition.X, WindowPosition.Y); IsFullscreen = FALSE; } else { /* TODO: This didn't work . . . SDL_GetError() */ } } else { - WindowSize = SDLGetWindowSize(Window); - WindowPosition = SDLGetWindowPosition(Window); + WindowSize = SDLGetBorderedWindowSize(Window); + WindowPosition = SDLGetBorderedWindowPosition(Window); if(SDL_SetWindowFullscreen(Window, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) { IsFullscreen = TRUE; @@ -773,7 +802,7 @@ S32 main(S32 argc, char *argv[]) if(Window) { SDL_DisplayMode display_mode; - SDL_GetCurrentDisplayMode(0, &display_mode); + SDL_GetCurrentDisplayMode(0, &display_mode); // Various display information. SDL_Renderer *Renderer = SDL_CreateRenderer(Window, -1, SDL_RENDERER_PRESENTVSYNC); @@ -789,6 +818,10 @@ S32 main(S32 argc, char *argv[]) thread_context TempContext; // TODO: memset(&TempContext, 0, sizeof(TempContext)); + // TODO: It should be in the handmade layer. Expose the SDLSetProgramIcon to handmade layer the same way we expose file writing. + // This way, we can use all the drawing functions of handmade. + // https://learn.microsoft.com/en-us/windows/apps/design/iconography/app-icon-construction + // Probably, the icon size should be 256x256, so windows scales it properly. This buffer should be allocated into the arena. loaded_bitmap ProgramIcon = DEBUGLoadBMPP(&TempContext, DEBUGPlatformReadEntireFile, "data/program_icon.bmp"); game_offscreen_buffer ProgramIconBuffer; ProgramIconBuffer.Memory = malloc((ProgramIcon.Width * ProgramIcon.Height) * 4); @@ -809,7 +842,11 @@ S32 main(S32 argc, char *argv[]) /* TODO: This didn't work . . . SDL_GetError() */ } #endif - SDL_SetWindowPosition(Window, (display_mode.w - RESOLUTION_WIDTH-20), (display_mode.h - RESOLUTION_HEIGHT-20)); + + SDL_Rect UsableDisplayRect; + SDL_GetDisplayUsableBounds(0, &UsableDisplayRect); + sdl_window_size CurrentWindowSize = SDLGetBorderedWindowSize(Window); + SDLSetBorderedWindowPosition(Window, (UsableDisplayRect.x + UsableDisplayRect.w - CurrentWindowSize.Width), (UsableDisplayRect.y + UsableDisplayRect.h - CurrentWindowSize.Height)); GlobalRunning = TRUE; @@ -828,8 +865,7 @@ S32 main(S32 argc, char *argv[]) SDL_PauseAudio(0); // TODO: This should be paused until we have some actual sound to play. SoundOutput.Samples = calloc(SoundOutput.SamplesPerSecond, SoundOutput.BytesPerSample); - /* SoundOutput.Samples = - * malloc(SoundOutput.SecondaryBufferSize); */ + /* SoundOutput.Samples = malloc(SoundOutput.SecondaryBufferSize); */ /* NOTE: calloc auto clears to zero */ /* SDLClearSoundBuffer(&SoundOutput); */ diff --git a/sdl_handmade.h b/sdl_handmade.h index 483454b..32f359b 100644 --- a/sdl_handmade.h +++ b/sdl_handmade.h @@ -6,6 +6,13 @@ #include "core.h" #include "handmade.h" +typedef struct sdl_border_size { + S32 Top; + S32 Bottom; + S32 Left; + S32 Right; +} sdl_border_size; + typedef struct sdl_window_size { S32 Width; S32 Height;