In this lesson, we'll explore SDL's window positioning capabilities, from setting initial window locations to handling dynamic repositioning. We’ll cover
As we’ve seen, the primary way we create windows within an SDL application is by using the SDL_CreateWindow()
function. The second and third arguments to SDL_CreateWindow()
define where we want the window to be positioned within the user’s screen.
These arguments represent the horizontal and vertical positions respectively. Below, we open a window 100 points from the left edge of the screen, and 200 points from the top edge:
SDL_CreateWindow(
"Hello Window",
100, 200,
700, 300, 0);
SDL_WINDOWPOS_UNDEFINED
In most use cases, we have no particular need to be this specific with the window position. Instead, we can let the platform decide the best place to open it.
To do this, we can pass SDL_WINDOWPOS_UNDEFINED
to either or both of these parameters: which we can use to let the platform decide where to open the window:
SDL_CreateWindow(
"Hello Window",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
700, 300, 0);
This is a sensible default choice, as the platform developers will have put some thought into where to open windows such that the user experience is pleasant.
For example, they might open the window near where the user clicked the icon to run the program, or they might open the program in the same location where the user placed it the last time they ran it.
SDL_WINDOWPOS_CENTERED
Alternatively, we can pass SDL_WINDOWPOS_CENTERED
to have SDL determine what position to use that would cause our window to be centered along either dimension. SDL examines the size of the monitor and the size of the window we’re creating (700x300 in this example) to determine what value would cause that window to be centered.
Below, we open a window that is centered both horizontally and vertically:
SDL_CreateWindow(
"Hello Window",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
700, 300, 0);
Whilst we can specify where we want our window to be initially created, many platforms allow users to move the window elsewhere on their screen. This is typically done by, for example, dragging on the title bar.
We can get the current position of a window by passing its SDL_Window
pointer to the SDL_GetWindowPosition()
function. We pass two additional arguments, which should be pointers to integers:
int x, y;
SDL_GetWindowPosition(Window, &x, &y);
SDL_GetWindowPosition()
updates these integers with the window’s horizontal and vertical position respectively:
#include <SDL.h>
#include <iostream>
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* Window{
SDL_CreateWindow(
"Hello Window",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
700, 300, 0
)};
int x, y;
SDL_GetWindowPosition(Window, &x, &y);
std::cout << "Position: " << x << ", " << y;
SDL_Quit();
return 0;
}
Position: 930, 570
If we only care about the window’s position in one dimension, we can pass a nullptr
to the other:
// We only care about horizontal position
int x;
SDL_GetWindowPosition(Window, &x, nullptr);
// We only care about vertical position
int y;
SDL_GetWindowPosition(Window, nullptr, &y);
SDL_WINDOWEVENT_MOVED
EventsWhilst SDL_GetWindowPosition()
allows us to retrieve the position of a window at any time, when our specific need is to react to a window being moved, the event loop is usually the better approach.
SDL emits an SDL_WindowEvent
with an event
value of SDL_WINDOWEVENT_MOVED
when a window is moved. We can react to this event in the usual way:
#include <SDL.h>
#include <iostream>
#include "Window.h"
void HandleWindowEvent(SDL_WindowEvent& E) {
if (E.event == SDL_WINDOWEVENT_MOVED) {
std::cout << "Window Moved\n";
}
}
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_VIDEO);
Window GameWindow;
SDL_Event E;
while (true) {
while (SDL_PollEvent(&E)) {
if (E.type == SDL_WINDOWEVENT) {
HandleWindowEvent(E.window);
} else if (E.type == SDL_QUIT) {
SDL_Quit();
return 0;
}
}
GameWindow.Update();
GameWindow.Render();
}
}
Window Moved
The data1
and data2
members of this event will contain the new horizontal and vertical position of the window respectively:
#include <SDL.h>
#include <iostream>
#include "Window.h"
void HandleWindowEvent(SDL_WindowEvent& E) {
if (E.event == SDL_WINDOWEVENT_MOVED) {
std::cout << "Window Moved: "
<< E.data1 << ", " << E.data2 << '\n';
}
}
int main(int argc, char** argv) {/*...*/}
Window Moved: 506, 281
We can update the position of an SDL_Window*
at any time using the SDL_SetWindowPosition()
function. This function accepts the SDL_Window*
as the first argument, and the window’s new horizontal and vertical positions as the second and third arguments respectively.
Let’s add this capability to our custom Window
class by introducing a Move()
method:
// Window.h
#pragma once
#include <SDL.h>
class Window {
public:
// ...
void Move(int x, int y) {
SDL_SetWindowPosition(SDLWindow, x, y);
}
SDL_Window* SDLWindow;
};
Just like when we initially created the window, we can pass SDL_WINDOWPOS_UNDEFINED
to the positional arguments of SDL_SetWindowPosition()
to let the platform decide the best values:
#include <SDL.h>
#include "Window.h"
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_VIDEO);
Window GameWindow;
GameWindow.Move(
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED
);
SDL_Quit();
return 0;
}
We can also use SDL_WINDOWPOS_CENTERED
to let SDL calculate the value that would cause the window to be centered along either dimension. Below, we move the window to the center of the screen if the user presses their spacebar whilst our window has input focus:
#include <SDL.h>
#include <iostream>
#include "Window.h"
void HandleKeydownEvent(
SDL_KeyboardEvent& E, Window& Window
) {
if (E.keysym.sym == SDLK_SPACE) {
Window.Move(
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED);
}
}
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_VIDEO);
Window GameWindow;
SDL_Event E;
while (true) {
while (SDL_PollEvent(&E)) {
if (E.type == SDL_KEYDOWN) {
HandleKeydownEvent(E.key, GameWindow);
} else if (E.type == SDL_QUIT) {
SDL_Quit();
return 0;
}
}
GameWindow.Update();
GameWindow.Render();
}
}
SDL_GetWindowFromID()
The event handler in the previous example requires access to a pointer to the SDL_Window
that it needs to resize. We accomplished this by providing an additional argument - a reference to our GameWindow
object that includes the SDL_Window*
as a member variable:
HandleKeydownEvent(E.key, GameWindow);
This is a valid approach for the simple example above, but it is not always possible. For example, if our program contains multiple windows, we won’t necessarily know which one caused the event to show up in our event loop.
An alternative approach involves retrieving the SDL_Window*
from the event itself. Most event types, including SDL_KeyboardEvent
, include a windowID
that identifies the window associated with the event.
By passing this value to SDL_GetWindowFromID()
, we can retrieve the corresponding SDL_Window
pointer:
void HandleKeydownEvent(SDL_KeyboardEvent& E) {
if (E.keysym.sym == SDLK_SPACE) {
SDL_SetWindowPosition(
SDL_GetWindowFromID(E.windowID),
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED);
}
}
When our program needs to move a window, the position we want to move it to will often depend on its current position. Rather than setting a position relative to the top left of the screen, we want to set a position relative to where the window currently is.
To do this, we can combine the SDL_GetWindowPosition()
and SDL_SetWindowPosition()
functions.
#include <SDL.h>
#include "Window.h"
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_VIDEO);
Window GameWindow;
int x, y;
SDL_GetWindowPosition(
GameWindow.SDLWindow, &x, &y);
// Move the window 10 pixels right
SDL_SetWindowPosition(
GameWindow.SDLWindow, x + 10, y);
SDL_Quit();
return 0;
}
Let’s update our Window
class with a generalized form of this capability, in the form of a method called MoveRelative()
:
// Window.h
#pragma once
#include <iostream>
#include <SDL.h>
class Window {
public:
void MoveRelative(int DeltaX, int DeltaY) {
int CurrentX, CurrentY;
SDL_GetWindowPosition(
SDLWindow, &CurrentX, &CurrentY);
SDL_SetWindowPosition(
SDLWindow,
CurrentX + DeltaX,
CurrentY + DeltaY);
}
SDL_Window* SDLWindow;
};
In the following example, we use this to let the user move their window with their arrow keys:
#include <SDL.h>
#include "Window.h"
void HandleKeydownEvent(
SDL_KeyboardEvent& E, Window& GameWindow) {
if (E.keysym.sym == SDLK_LEFT) {
GameWindow.MoveRelative(-10, 0);
} else if (E.keysym.sym == SDLK_RIGHT) {
GameWindow.MoveRelative(10, 0);
} else if (E.keysym.sym == SDLK_UP) {
GameWindow.MoveRelative(0, -10);
} else if (E.keysym.sym == SDLK_DOWN) {
GameWindow.MoveRelative(0, 10);
}
}
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_VIDEO);
Window GameWindow;
SDL_Event E;
while (true) {
while (SDL_PollEvent(&E)) {
if (E.type == SDL_KEYDOWN) {
HandleKeydownEvent(E.key, GameWindow);
} else if (E.type == SDL_QUIT) {
SDL_Quit();
return 0;
}
}
GameWindow.Update();
GameWindow.Render();
}
}
In this lesson, we've covered the fundamentals of window positioning in SDL2. We've learned how to control window placement both at creation and during runtime, respond to window movement events, and implement relative movement. Key takeaways:
SDL_WINDOWPOS_UNDEFINED
and SDL_WINDOWPOS_CENTERED
.SDL_GetWindowPosition()
lets us query a window's current location.SDL_SetWindowPosition()
allows programmatic window movement.SDL_WINDOWEVENT_MOVED
) help us track user-initiated window changes.Learn how to control and monitor the position of SDL windows on screen
Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games