Transparent window background on Windows (SDL2)
One of my recent projects required me to create a desktop window with transparent background. I was using SDL, however the method should be applicable for any technology which is capable of calling the Windows API.
Obtaining the window handle
In order to use the Windows API functions you need a window handle. In SDL you can obtain it using the following function:
#ifndef _WIN32 #error "This code only works on Windows" #endif #include <windows.h> HWND window_handle(SDL_Window *window) { SDL_SysWMInfo wmInfo; SDL_VERSION(&wmInfo.version); SDL_GetWindowWMInfo(window, &wmInfo); HWND hwnd = wmInfo.info.win.window; return hwnd; }
Setting the transparency attribute
Every window has a property called a transparency key. This attribute is a color
which will be rendered as transparent. Obviously, you should choose a rarely used color, such as magenta.
You can set the attribute using the
SetLayeredWindowAttributes()
function, however, as the name of the function
indicates, the window must be layered. To achieve this, you need to use the
SetWindowLong()
function. A good overview of how windows work can be found
in
Microsoft documentation.
// Any pixel of this color will be rendered as transparent const COLORREF transparent_colorref = RGB(255, 0, 255); /** * Returns 0 on failure, 1 on success. Sets up the given window for rendering transparent pixels. */ int enable_transparency(SDL_Window *window) { HWND handle = window_handle(window); if(!SetWindowLong(handle, GWL_EXSTYLE, GetWindowLong(handle, GWL_EXSTYLE) | WS_EX_LAYERED)) { fprintf(stderr, "SetWindowLong Error\n"); return 0; } if(!SetLayeredWindowAttributes(handle, transparent_colorref, 0, 1)) { fprintf(stderr, "SetLayeredWindowAttributes Error\n"); return 0; } return 1; }
Drawing transparent pixels
Once the window has been set up, you can draw transparent pixels simply by setting the draw color to whatever color you chose for the transparency key.
/** * Fills the entire renderer with transparent background. */ void draw_transparent_background(SDL_Renderer *renderer) { SDL_SetRenderDrawColor(renderer, GetRValue(transparent_colorref), GetGValue(transparent_colorref), GetBValue(transparent_colorref), SDL_ALPHA_OPAQUE); SDL_RenderFillRect(renderer, NULL); }
Full code
#ifndef _WIN32 #error "This code only works on Windows" #endif #include <stdio.h> #include <SDL2/SDL.h> #include <SDL2/SDL_syswm.h> #include <windows.h> static HWND window_handle(SDL_Window *window) { SDL_SysWMInfo wmInfo; SDL_VERSION(&wmInfo.version); SDL_GetWindowWMInfo(window, &wmInfo); HWND hwnd = wmInfo.info.win.window; return hwnd; } // Any pixel of this color will be rendered as transparent static const COLORREF transparent_colorref = RGB(255, 0, 255); /** * Returns 0 on failure, 1 on success. Sets up the given window for rendering transparent pixels. */ int enable_transparency(SDL_Window *window) { HWND handle = window_handle(window); if(!SetWindowLong(handle, GWL_EXSTYLE, GetWindowLong(handle, GWL_EXSTYLE) | WS_EX_LAYERED)) { fprintf(stderr, "SetWindowLong Error\n"); return 0; } if(!SetLayeredWindowAttributes(handle, transparent_colorref, 0, 1)) { fprintf(stderr, "SetLayeredWindowAttributes Error\n"); return 0; } return 1; } /** * Fills the entire renderer with transparent background. */ void draw_transparent_background(SDL_Renderer *renderer) { SDL_SetRenderDrawColor(renderer, GetRValue(transparent_colorref), GetGValue(transparent_colorref), GetBValue(transparent_colorref), SDL_ALPHA_OPAQUE); SDL_RenderFillRect(renderer, NULL); }