Window Events and Window IDs
Discover how to monitor and respond to window state changes in SDL applications
Previously, we've seen how we can retrieve aspects of our window's configuration by checking its window flags. However, we don't need to continuously monitor our SDL_Window
to understand its state.
For most use cases, monitoring the event loop makes more sense. SDL dispatches a wide variety of events reporting actions performed on our window. In this lesson, we'll explore this in a bit more detail.
The SDL_WindowEvent
Type
SDL_Event
objects that correspond to window events will have a type
of SDL_WINDOWEVENT
. If an SDL_Event
has the SDL_WINDOWEVENT
type, a more specific SDL_WindowEvent
is available within the window
variable:
// main.cpp
#include <SDL.h>
#include <iostream>
#include "Window.h"
void HandleWindowEvent(SDL_WindowEvent& E) {
std::cout << "Detected Window Event\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();
}
}
Detected Window Event
Detected Window Event
Detected Window Event
Window events are used to report a wide range of actions, covering events like the window being resized, moved, and minimized. The nature of the event is available within the event
variable of an SDL_WindowEvent
. This variable has a type of SDL_WindowEventID
, with possible values being listed in the official documentation.
We'll cover many of these events and how to make use of them throughout the remainder of this chapter. In this example, we implement a basic reaction to just a few of them:
#include <SDL.h>
#include <iostream>
#include "Window.h"
void HandleWindowEvent(SDL_WindowEvent& E) {
if (E.event == SDL_WINDOWEVENT_MINIMIZED) {
std::cout << "Window Minimized\n";
} else if (E.event == SDL_WINDOWEVENT_MOVED) {
std::cout << "Window Moved\n";
} else if (E.event == SDL_WINDOWEVENT_ENTER) {
std::cout << "Cursor Entered the Window\n";
}
}
int main(int argc, char** argv) {/*...*/}
Cursor Entered the Window
Window Moved
Window Minimized
Example: Mouse Entering and Leaving Window
In this example, we'll react to the user's cursor entering and leaving our window. We'll use the SDL_SetWindowTitle()
function to change the title based on these events:
#include <SDL.h>
#include <iostream>
void HandleWindowEvent(SDL_WindowEvent& E, SDL_Window* Window) {
if (E.event == SDL_WINDOWEVENT_ENTER) {
SDL_SetWindowTitle(Window, "Mouse Inside the Window");
} else if (E.event == SDL_WINDOWEVENT_LEAVE) {
SDL_SetWindowTitle(Window, "Mouse Outside the Window");
}
}
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, GameWindow.SDLWindow);
} else if (E.type == SDL_QUIT) {
SDL_Quit();
return 0;
}
}
GameWindow.Render();
GameWindow.Update();
}
}
Window IDs
In the previous example, our HandleWindowEvent()
logic requires a pointer to the SDL_Window
it needs to change the title of. We did this by passing it to the handler as a second argument, but it's also possible to retrieve the SDL_Window
from the SDL_WindowEvent
.
Internally, SDL assigns a unique identifier to each window it creates, in the form of a simple integer. The ID of the window associated with the event is available on the windowID
member of the SDL_WindowEvent
:
#include <SDL.h>
#include <iostream>
#include "Window.h"
void HandleKeydownEvent(SDL_KeyboardEvent& E) {
if (E.keysym.sym == SDLK_SPACE) {
std::cout << "\nWindowID: " << E.windowID;
}
}
int main(int argc, char** argv) {/*...*/}
WindowID: 1
Above, we're responding to an SDL_WindowEvent
, but this windowID
variable exists on every event type that relates to a specific window. This includes types like SDL_KeyboardEvent
, where the windowID
will be the window with input focus, and SDL_MouseMotionEvent
and SDL_MouseButtonEvent
, where the ID will be the window the mouse is hovering over.
Getting an SDL_Window*
Using SDL_GetWindowFromID()
By passing this window ID to SDL_GetWindowFromID()
, we get the corresponding SDL_Window
pointer:
SDL_Window* Win{SDL_GetWindowFromID(E.windowID)};
Below, we update our previous program to combine these techniques to position the SDL_Window
directly, rather than passing a reference to our Window
object to our event handler and using our Move()
method:
#include <SDL.h>
#include <iostream>
#include "Window.h"
void HandleKeydownEvent(SDL_KeyboardEvent& E) {
if (E.keysym.sym == SDLK_SPACE) {
SDL_SetWindowPosition(
SDL_GetWindowFromID(E.windowID),
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED);
}
}
int main(int argc, char** argv) {/*...*/}
The SDL_GetWindowFromID()
approach is unnecessary in this case - it's easier to use the initial technique where we simply provided a reference to our GameWindow
to the event handler.
However, using SDL_GetWindowFromID()
becomes valuable in multi-window applications, where we need to know which specific window should respond to user input. We cover multi-window applications and window IDs in more detail later in this chapter.
Getting a Window ID Using SDL_GetWindowID()
We can perform this conversion in the opposite direction using SDL_GetWindowID()
. We pass it the SDL_Window
pointer, and it returns the window ID associated with that SDL_Window
:
#include <SDL.h>
#include <iostream>
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* Window = SDL_CreateWindow(
"Window ID Example",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
800,
600,
SDL_WINDOW_SHOWN
);
int WindowID = SDL_GetWindowID(Window);
std::cout << "The ID of the created window is: "
<< WindowID << '\n';
SDL_DestroyWindow(Window);
SDL_Quit();
return 0;
}
The ID of the created window is: 1
One scenario where this might be useful is when we're using SDL's event system for custom events within our game. SDL provides the SDL_UserEvent
type for this purpose, and it includes a windowID
member which we can provide if needed:
Uint32 GAME_OVER{SDL_RegisterEvents(1)};
SDL_Event MyEvent{GAME_OVER};
MyEvent.user.windowID = SDL_GetWindowID(Window);
SDL_PushEvent(&MyEvent);
We can then retrieve the SDL_Window
associated with the event within its handlers:
void HandleGameOverEvent(SDL_UserEvent& E){
SDL_Window* Window{
SDL_GetWindowFromID(E.windowID)};
// ...
}
We covered user events in a dedicated lesson earlier in the course:
Creating Custom Events
Learn how to create and manage your own game-specific events using SDL's event system.
Summary
In this lesson, we explored more of SDL's window management systems, focusing on window events and unique identifiers. Key takeaways:
SDL_WindowEvent
captures specific window-related actions like moving, resizing, or minimizing.- Window IDs uniquely identify SDL windows.
- Use
SDL_GetWindowFromID()
to retrieve anSDL_Window*
from a window ID andSDL_GetWindowID()
to find the ID associated with anSDL_Window*
.
Managing Window Position
Learn how to control and monitor the position of SDL windows on screen