How to make an SDL window the child of another window in Win32

This had me beating my head against the wall for days. Now as you know, It is fairly straightforward to open an SDL surface in a window:

SDL_Surface *screen = SDL_SetVideoMode(width, height, 24, SDL_NOFRAME);
if(screen == 0)
    throw AVException(SDL_GetError());

The SDL_NOFRAME option removes the window borders so the window is now ready to become a child window. Next we need to obtain the SDL window’s HWND

#include <SDL_syswm.h>

struct SDL_SysWMinfo wmInfo;
SDL_VERSION(&wmInfo.version);

if(-1 == SDL_GetWMInfo(&wmInfo))
    throw AVException(SDL_GetError());

HWND hwndSDL = wmInfo.window;

Now we can parent it to our window:

SetParent(hwndSDL, hwndMyWindow);

So far so good but this is where it all falls apart. When the parent window is moved, the SDL window does not move with it. You get an effect where the clipping rectangle moves but the contents of the window stay put.

This took me days to figure out. It tried messsing about with WM_MOVE handlers and using offsets on my SDL_UpdateRect() coordinates and all kinds of crazy stuff but in the end I found two important facts:

  1. The SDL window does not receive WM_MOVE noftifications from its parent
  2. Using MoveWindow to set the position of the SDL window does not work if the new coordinates are the same as the current coordinates (that was the tough one to work out)

Since I am using SDL to play video, I am constantly updating the window all the time. This means I can use a test in my update function to check if the window has moved. If so, I need to use two calls to MoveWindow to fool SDL into moving. If you are not doing animation, perhaps you could use a timer call or something to achieve the same result. Anyway, here is the code:

// Dumps the given frame to the screen.
void showFrame(SDL_Surface *surface)
{
    static RECT lastPos;

// Check to see if the window has been moved.
    RECT r;
    GetWindowRect(hwndSDL, &r);

    if(r.left != lastPos.left || r.top != lastPos.top)
    {
        GetClientRect(hwndSDL, &r);
        MoveWindow(hwndSDL, r.left, r.top, r.right - r.left, r.bottom - r.top, FALSE);
        MoveWindow(hwndSDL, r.left + 4, r.top, r.right - r.left, r.bottom - r.top, FALSE);
        lastPos = r;
    }

// Copy the off-screen surface to the screen.
    SDL_BlitSurface(surface, 0, screen, 0);
    SDL_UpdateRect(screen, 0, 0, 0, 0);
}