Managing Window Position
Learn how to control and monitor the position of SDL windows on screen
In this lesson, we'll explore SDL's window positioning capabilities, from setting initial window locations to handling dynamic repositioning. We'll cover
- How to set window positions explicitly, or use special values that dynamically position our window based on the environment our program is run on
- Retrieving the current location of our window
- Moving windows programmatically, including how to shift a window based on its current position
- Detecting when the user moves our window, so we can respond appropriately
- A preview of window IDs, which let us manage events in applications that have multiple windows
Window Position
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);
Using 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.
Using 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);
Getting the Window Position
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);
Window Movement Events and SDL_WINDOWEVENT_MOVED
Whilst 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.Render();
GameWindow.Update();
}
}
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
Programmatically Moving a Window
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.Render();
GameWindow.Update();
}
}
Relative Moving
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.Render();
GameWindow.Update();
}
}
Summary
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:
- Window positions can be specified explicitly or using special values like
SDL_WINDOWPOS_UNDEFINED
andSDL_WINDOWPOS_CENTERED
. SDL_GetWindowPosition()
lets us query a window's current location.SDL_SetWindowPosition()
allows programmatic window movement.- Window movement events (
SDL_WINDOWEVENT_MOVED
) help us track user-initiated window changes. - Relative movement can be implemented by combining position getting and setting.
- Window IDs provide a reliable way to track and manage multiple windows.
Window Sizing
Learn how to resize, constrain, and manage SDL2 windows