Window Decorations and Borders

An introduction to managing SDL3 window decorations, borders, and client areas.

Ryan McCombe
Updated

As we've likely noticed, platforms typically add decorations to our windows, such as a title bar and borders. But what if you need a clean, borderless look?

In this lesson, we'll cover everything you need to know about customizing SDL3 window styles, including removing decorations and dynamically adding them back.

The following screenshot is from Windows 11. It shows a decorated window on the left and an equivalent window without those decorations on the right:

SDL refers to these decorations as borders but, as we can see above, they can also include things like the title bar on desktop platforms.

Starting Point

This lesson builds on our earlier work. To focus on window borders, we will start with a minimal project containing a Window class and a main function with a basic application loop:

Files

src
Select a file to view its content

Creating a Borderless Window

By default, SDL asks the platform to include these decorations for our window. We can opt to exclude them by passing the SDL_WINDOW_BORDERLESS window flag to SDL_CreateWindow():

src/Window.h

#pragma once
#include <SDL3/SDL.h>

class Window {
public:
  Window() {
    SDLWindow = SDL_CreateWindow(
      "My Program", 600, 300,
      SDL_WINDOW_BORDERLESS
    );
  }
  // ...
};

Running this code will produce a clean, undecorated window.

Adding and Removing Borders

We can add or remove decorations from an existing window using the SDL_SetWindowBordered() function. We pass the SDL_Window pointer as the first argument, and true or false as the second argument.

Let's add a SetBordered() method to our Window class to encapsulate this functionality:

src/Window.h

#pragma once
#include <SDL3/SDL.h>

class Window {
public:
  // ...
  void SetBordered(bool Bordered) {
    SDL_SetWindowBordered(GetRaw(), Bordered);
  }
  // ...
};

Now we can toggle the border from our main function. For example, we could remove the border when the 'B' key is pressed:

src/main.cpp

#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include "Window.h"

int main(int, char**) {
  SDL_Init(SDL_INIT_VIDEO);
  Window GameWindow;
  SDL_Event Event;

  bool IsRunning = true;
  while (IsRunning) {
    while (SDL_PollEvent(&Event)) {
      if (Event.type == SDL_EVENT_KEY_DOWN &&
          Event.key.key == SDLK_B) {
        GameWindow.SetBordered(false);
      } else if (Event.type == SDL_EVENT_QUIT) {
        IsRunning = false;
      }
    }
    GameWindow.Render();
    GameWindow.Update();
  }

  SDL_Quit();
  return 0;
}

We can check if a window currently has borders by retrieving its flags with SDL_GetWindowFlags() and testing if the SDL_WINDOW_BORDERLESS flag is set. Let's add an IsBorderless() helper to our Window class:

src/Window.h

#pragma once
#include <SDL3/SDL.h>

class Window {
public:
  // ...
  bool IsBorderless() const {
    return (SDL_GetWindowFlags(GetRaw()) &
      SDL_WINDOW_BORDERLESS) != 0;
  }
  // ...
};

We can now use this method to check the window's state:

src/main.cpp

#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <iostream>
#include "Window.h"

int main(int, char**) {
  SDL_Init(SDL_INIT_VIDEO);
  Window GameWindow;
  GameWindow.SetBordered(false);

  if (GameWindow.IsBorderless()) {
    std::cout << "Window is borderless\n";
  }

  GameWindow.SetBordered(true);

  if (!GameWindow.IsBorderless()) {
    std::cout << "Not any more!";
  }

  // ... (rest of the main function)
}
Window is borderless
Not any more!

Client Area and Border Size

When setting the position or size of a window in SDL, we are defining the dimensions of the client area. The client area is the region of the window where the application's content is displayed, excluding any decorations like the title bar or window borders.

Decorations are added outside the client area. For instance, if you specify a window height of 200, the client area will be exactly 200 points tall, but the total window height will also include the additional space occupied by decorations.

To precisely control the overall window size or position, it's important to account for the size of these decorations.

The SDL_GetWindowBordersSize() function can help us here. We pass the SDL_Window pointer and four integer pointers. The integers will be updated with the size of the decorations on the top, left, bottom, and right of our window respectively:

src/main.cpp

#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <iostream>
#include "Window.h"

int main(int, char**) {
  SDL_Init(SDL_INIT_VIDEO);
  Window GameWindow;

  int Top, Left, Bottom, Right;
  SDL_GetWindowBordersSize(
    GameWindow.GetRaw(),
    &Top, &Left, &Bottom, &Right
  );

  std::cout << "Top: " << Top
    << ", Left: " << Left
    << ", Bottom: " << Bottom
    << ", Right: " << Right << '\n';

  // ... (rest of the main function)
}
Top: 31, Left: 8, Bottom: 8, Right: 8

We can pass a nullptr for any of these arguments to ignore the decoration size on that side. For example, passing nullptr for the left and right pointers will only return the sizes of the top and bottom decorations.

// We only care about the top and bottom decoration size
int Top, Bottom;
SDL_GetWindowBordersSize(
  GameWindow.GetRaw(),
  &Top,
  nullptr,
  &Bottom,
  nullptr
);

This function returns 0 if successful, or a negative error code otherwise. We can call SDL_GetError() for an explanation of the error, a technique covered in our lesson on .

int Top;
int ExitCode = SDL_GetWindowBordersSize(
  nullptr, &Top, nullptr, nullptr, nullptr);  

if (ExitCode < 0) {
  std::cout << "Error getting border size: "
    << SDL_GetError();
}
Error getting border size: Invalid window

Summary

In this lesson, we introduced window decorations and how to control them. This included making windows borderless and measuring their decorations for precise layout control.

Key Takeaways

  • SDL provides the SDL_WINDOW_BORDERLESS flag to create borderless windows.
  • Use SDL_SetWindowBordered() to dynamically toggle decorations.
  • The SDL_GetWindowBordersSize() function helps calculate the size of window decorations.
Next Lesson
Lesson 54 of 61

Window Titles

Learn how to set, get, and update window titles dynamically

Have a question about this lesson?
Answers are generated by AI models and may not be accurate