# HG changeset patch # User Sam Lantinga # Date 1151482327 0 # Node ID 5b9f50c957ed457b52e9a09c13ca0b93692b4903 # Parent ed4d4f1ea2010b07a1e155313f01164d1479fe1d You can now create multiple windows on Win32 diff -r ed4d4f1ea201 -r 5b9f50c957ed include/SDL_video.h --- a/include/SDL_video.h Tue Jun 27 07:46:36 2006 +0000 +++ b/include/SDL_video.h Wed Jun 28 08:12:07 2006 +0000 @@ -116,18 +116,29 @@ typedef enum { SDL_WINDOW_FULLSCREEN = 0x00000001, /**< fullscreen window, implies borderless */ - SDL_WINDOW_BORDERLESS = 0x00000002, /**< no window decoration */ + SDL_WINDOW_OPENGL = 0x00000002, /**< window usable with OpenGL context */ SDL_WINDOW_SHOWN = 0x00000004, /**< window is visible */ - SDL_WINDOW_OPENGL = 0x00000008, /**< window usable with OpenGL context */ + SDL_WINDOW_BORDERLESS = 0x00000008, /**< no window decoration */ SDL_WINDOW_RESIZABLE = 0x00000010, /**< window can be resized */ SDL_WINDOW_MAXIMIZED = 0x00000020, /**< maximized */ SDL_WINDOW_MINIMIZED = 0x00000040, /**< minimized */ - SDL_WINDOW_INPUT_GRABBED = 0x00000080, /**< window has grabbed input focus */ - SDL_WINDOW_KEYBOARD_FOCUS = 0x00000100, /**< window has keyboard focus */ - SDL_WINDOW_MOUSE_FOCUS = 0x00000200, /**< window has mouse focus */ + SDL_WINDOW_INPUT_GRABBED = 0x00000100, /**< window has grabbed input focus */ + SDL_WINDOW_KEYBOARD_FOCUS = 0x00000200, /**< window has keyboard focus */ + SDL_WINDOW_MOUSE_FOCUS = 0x00000400, /**< window has mouse focus */ } SDL_WindowFlags; /** + * \def SDL_WINDOWPOS_UNDEFINED + * \brief Used to indicate that you don't care what the window position is. + */ +#define SDL_WINDOWPOS_UNDEFINED 0x7FFFFFF +/** + * \def SDL_WINDOWPOS_CENTERED + * \brief Used to indicate that the window position should be centered. + */ +#define SDL_WINDOWPOS_CENTERED 0x7FFFFFE + +/** * \enum SDL_WindowEventID * * \brief Event subtype for window events @@ -584,6 +595,12 @@ * * \brief Set the position of the window. * + * \param windowID The window to reposition + * \param x The x coordinate of the window, SDL_WINDOWPOS_CENTERED, or SDL_WINDOWPOS_UNDEFINED + * \param y The y coordinate of the window, SDL_WINDOWPOS_CENTERED, or SDL_WINDOWPOS_UNDEFINED + * + * \note The window coordinate origin is the upper left of the display. + * * \sa SDL_GetWindowPosition() */ extern DECLSPEC void SDLCALL SDL_SetWindowPosition(SDL_WindowID windowID, @@ -737,7 +754,7 @@ * * \brief Create and make active a 2D rendering context for a window. * - * \param windowID The window used for rendering. + * \param windowID The window used for rendering * \param index The index of the render manager to initialize, or -1 to initialize the first one supporting the requested flags. * \param flags SDL_RendererFlags * diff -r ed4d4f1ea201 -r 5b9f50c957ed src/video/SDL_video.c --- a/src/video/SDL_video.c Tue Jun 27 07:46:36 2006 +0000 +++ b/src/video/SDL_video.c Wed Jun 28 08:12:07 2006 +0000 @@ -647,9 +647,9 @@ SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags) { const Uint32 allowed_flags = (SDL_WINDOW_FULLSCREEN | - SDL_WINDOW_BORDERLESS | + SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | - SDL_WINDOW_OPENGL | + SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED | @@ -842,8 +842,12 @@ return; } - window->x = x; - window->y = y; + if (x != SDL_WINDOWPOS_UNDEFINED) { + window->x = x; + } + if (y != SDL_WINDOWPOS_UNDEFINED) { + window->y = y; + } if (_this->SetWindowPosition) { _this->SetWindowPosition(_this, window); diff -r ed4d4f1ea201 -r 5b9f50c957ed src/video/win32/SDL_win32events.c --- a/src/video/win32/SDL_win32events.c Tue Jun 27 07:46:36 2006 +0000 +++ b/src/video/win32/SDL_win32events.c Wed Jun 28 08:12:07 2006 +0000 @@ -24,10 +24,20 @@ #include "SDL_win32video.h" -static LRESULT CALLBACK -WinMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +LRESULT CALLBACK +WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam); + SDL_WindowData *data; + SDL_Window *window; + + /* Get the window data for the window */ + data = (SDL_WindowData *) GetProp(hwnd, TEXT("SDL_WindowData")); + if (!data) { + return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam); + } + window = data->window; + + return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam); } void @@ -63,7 +73,7 @@ } if (name) { - SDL_Appname = SDL_iconv_utf8_ucs2(name); + SDL_Appname = WIN_UTF8ToString(name); SDL_Appstyle = style; SDL_Instance = hInst ? hInst : GetModuleHandle(NULL); } @@ -77,7 +87,7 @@ class.hbrBackground = NULL; class.hInstance = SDL_Instance; class.style = SDL_Appstyle; - class.lpfnWndProc = WinMessage; + class.lpfnWndProc = DefWindowProc; class.cbWndExtra = 0; class.cbClsExtra = 0; if (!RegisterClass(&class)) { @@ -110,4 +120,20 @@ } } +/* Sets an error message based on GetLastError() */ +void +WIN_SetError(const char *prefix) +{ + TCHAR buffer[1024]; + char *message; + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), 0, buffer, SDL_arraysize(buffer), NULL); + + message = WIN_StringToUTF8(buffer); + SDL_SetError("%s%s%s", prefix ? prefix : "", prefix ? ":" : "", message); + SDL_free(message); +} + /* vi: set ts=4 sw=4 expandtab: */ diff -r ed4d4f1ea201 -r 5b9f50c957ed src/video/win32/SDL_win32events.h --- a/src/video/win32/SDL_win32events.h Tue Jun 27 07:46:36 2006 +0000 +++ b/src/video/win32/SDL_win32events.h Wed Jun 28 08:12:07 2006 +0000 @@ -24,13 +24,14 @@ #ifndef _SDL_win32events_h #define _SDL_win32events_h -#include "../SDL_sysvideo.h" - extern LPTSTR SDL_Appname; extern Uint32 SDL_Appstyle; extern HINSTANCE SDL_Instance; +extern LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, + LPARAM lParam); extern void WIN_PumpEvents(_THIS); +extern void WIN_SetError(const char *prefix); #endif /* _SDL_win32events_h */ diff -r ed4d4f1ea201 -r 5b9f50c957ed src/video/win32/SDL_win32video.h --- a/src/video/win32/SDL_win32video.h Tue Jun 27 07:46:36 2006 +0000 +++ b/src/video/win32/SDL_win32video.h Wed Jun 28 08:12:07 2006 +0000 @@ -33,6 +33,14 @@ #include "SDL_win32events.h" #include "SDL_win32window.h" +#ifdef UNICODE +#define WIN_StringToUTF8(S) SDL_iconv_string("UTF-8", "UCS-2", (char *)S, (wcslen(S)+1)*sizeof(WCHAR)) +#define WIN_UTF8ToString(S) (WCHAR *)SDL_iconv_string("UCS-2", "UTF-8", (char *)S, SDL_strlen(S)+1) +#else +#define WIN_StringToUTF8(S) SDL_iconv_string("UTF-8", "ASCII", (char *)S, (strlen(S)+1)) +#define WIN_UTF8ToString(S) SDL_iconv_string("ASCII", "UTF-8", (char *)S, SDL_strlen(S)+1) +#endif + /* Private display data */ struct SDL_PrivateVideoData diff -r ed4d4f1ea201 -r 5b9f50c957ed src/video/win32/SDL_win32window.c --- a/src/video/win32/SDL_win32window.c Tue Jun 27 07:46:36 2006 +0000 +++ b/src/video/win32/SDL_win32window.c Wed Jun 28 08:12:07 2006 +0000 @@ -26,74 +26,378 @@ #include "SDL_win32video.h" +static int +SetupWindowData(SDL_Window * window, HWND hwnd, BOOL created) +{ + SDL_WindowData *data; + + /* Allocate the window data */ + data = (SDL_WindowData *) SDL_malloc(sizeof(*data)); + if (!data) { + SDL_OutOfMemory(); + return -1; + } + data->window = window; + data->hwnd = hwnd; + data->created = created; + + /* Associate the data with the window */ + if (!SetProp(hwnd, TEXT("SDL_WindowData"), data)) { + SDL_free(data); + WIN_SetError("SetProp() failed"); + return -1; + } + + /* Set up the window proc function */ + data->wndproc = (WNDPROC) GetWindowLongPtr(hwnd, GWLP_WNDPROC); + if (data->wndproc == NULL) { + data->wndproc = DefWindowProc; + } else { + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) WIN_WindowProc); + } + + /* Fill in the SDL window with the window data */ + { + POINT point; + if (ClientToScreen(hwnd, &point)) { + window->x = point.x; + window->y = point.y; + } + } + { + RECT rect; + if (GetClientRect(hwnd, &rect)) { + window->w = rect.right; + window->h = rect.bottom; + } + } + { + DWORD style = GetWindowLong(hwnd, GWL_STYLE); + if (style & WS_VISIBLE) { + window->flags |= SDL_WINDOW_SHOWN; + } else { + window->flags &= ~SDL_WINDOW_SHOWN; + } + if (style & (WS_BORDER | WS_THICKFRAME)) { + window->flags &= ~SDL_WINDOW_BORDERLESS; + } else { + window->flags |= SDL_WINDOW_BORDERLESS; + } + if (style & WS_THICKFRAME) { + window->flags |= SDL_WINDOW_RESIZABLE; + } else { + window->flags &= ~SDL_WINDOW_RESIZABLE; + } + if (style & WS_MAXIMIZE) { + window->flags |= SDL_WINDOW_MAXIMIZED; + } else { + window->flags &= ~SDL_WINDOW_MAXIMIZED; + } + if (style & WS_MINIMIZE) { + window->flags |= SDL_WINDOW_MINIMIZED; + } else { + window->flags &= ~SDL_WINDOW_MINIMIZED; + } + } + + /* All done! */ + window->driverdata = data; + return 0; +} + int WIN_CreateWindow(_THIS, SDL_Window * window) { + HWND hwnd; + LPTSTR title = NULL; + HWND top; + RECT rect; + DWORD style = 0; + int x, y; + int w, h; + + if (window->title) { + title = WIN_UTF8ToString(window->title); + } else { + title = NULL; + } + + if (window->flags & SDL_WINDOW_SHOWN) { + style |= WS_VISIBLE; + } + if ((window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS))) { + style |= WS_POPUP; + } else { + style |= (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX); + } + if (window->flags & SDL_WINDOW_RESIZABLE) { + style |= (WS_THICKFRAME | WS_MAXIMIZEBOX); + } + if (window->flags & SDL_WINDOW_MAXIMIZED) { + style |= WS_MAXIMIZE; + } + if (window->flags & SDL_WINDOW_MINIMIZED) { + style |= WS_MINIMIZE; + } + + /* Figure out what the window area will be */ + if (window->flags & SDL_WINDOW_FULLSCREEN) { + top = HWND_TOPMOST; + } else { + top = HWND_NOTOPMOST; + } + rect.left = 0; + rect.top = 0; + rect.right = window->w; + rect.bottom = window->h; + AdjustWindowRectEx(&rect, style, FALSE, 0); + w = (rect.right - rect.left); + h = (rect.bottom - rect.top); + + if ((window->flags & SDL_WINDOW_FULLSCREEN) || + window->x == SDL_WINDOWPOS_CENTERED) { + x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2; + } else if (window->x == SDL_WINDOWPOS_UNDEFINED) { + x = CW_USEDEFAULT; + } else { + x = window->x + rect.left; + } + if ((window->flags & SDL_WINDOW_FULLSCREEN) || + window->y == SDL_WINDOWPOS_CENTERED) { + y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2; + } else if (window->y == SDL_WINDOWPOS_UNDEFINED) { + y = CW_USEDEFAULT; + } else { + y = window->y + rect.top; + } + + hwnd = CreateWindow(SDL_Appname, + title ? title : TEXT(""), + style, x, y, w, h, NULL, NULL, SDL_Instance, NULL); + if (title) { + SDL_free(title); + } + + if (!hwnd) { + WIN_SetError("Couldn't create window"); + return -1; + } + + if (SetupWindowData(window, hwnd, TRUE) < 0) { + DestroyWindow(hwnd); + return -1; + } + return 0; } int WIN_CreateWindowFrom(_THIS, SDL_Window * window, const void *data) { + HWND hwnd = (HWND) data; + LPTSTR title; + int titleLen; + + /* Query the title from the existing window */ + titleLen = GetWindowTextLength(hwnd); + title = SDL_stack_alloc(TCHAR, titleLen + 1); + if (title) { + titleLen = GetWindowText(hwnd, title, titleLen); + } else { + titleLen = 0; + } + if (titleLen > 0) { + window->title = WIN_StringToUTF8(title); + } + if (title) { + SDL_stack_free(title); + } + + if (SetupWindowData(window, hwnd, FALSE) < 0) { + return -1; + } + return 0; } void WIN_SetWindowTitle(_THIS, SDL_Window * window) { + HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; + LPTSTR title; + + if (window->title) { + title = WIN_UTF8ToString(window->title); + } else { + title = NULL; + } + SetWindowText(hwnd, title ? title : TEXT("")); + if (title) { + SDL_free(title); + } } void WIN_SetWindowPosition(_THIS, SDL_Window * window) { + HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; + RECT rect; + DWORD style; + HWND top; + int x, y; + int w, h; + + /* Figure out what the window area will be */ + if (window->flags & SDL_WINDOW_FULLSCREEN) { + top = HWND_TOPMOST; + } else { + top = HWND_NOTOPMOST; + } + style = GetWindowLong(hwnd, GWL_STYLE); + rect.left = 0; + rect.top = 0; + rect.right = window->w; + rect.bottom = window->h; + AdjustWindowRectEx(&rect, style, + (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != + NULL), 0); + w = (rect.right - rect.left); + h = (rect.bottom - rect.top); + + if ((window->flags & SDL_WINDOW_FULLSCREEN) || + window->x == SDL_WINDOWPOS_CENTERED) { + x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2; + window->x = x - rect.left; + } else { + x = window->x + rect.left; + } + if ((window->flags & SDL_WINDOW_FULLSCREEN) || + window->y == SDL_WINDOWPOS_CENTERED) { + y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2; + window->y = y - rect.top; + } else { + y = window->y + rect.top; + } + SetWindowPos(hwnd, top, x, y, h, w, (SWP_NOCOPYBITS | SWP_NOSIZE)); } void WIN_SetWindowSize(_THIS, SDL_Window * window) { + HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; + RECT rect; + DWORD style; + HWND top; + int w, h; + + /* Figure out what the window area will be */ + if (window->flags & SDL_WINDOW_FULLSCREEN) { + top = HWND_TOPMOST; + } else { + top = HWND_NOTOPMOST; + } + style = GetWindowLong(hwnd, GWL_STYLE); + rect.left = 0; + rect.top = 0; + rect.right = window->w; + rect.bottom = window->h; + AdjustWindowRectEx(&rect, style, + (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != + NULL), 0); + w = (rect.right - rect.left); + h = (rect.bottom - rect.top); + + SetWindowPos(hwnd, top, 0, 0, h, w, (SWP_NOCOPYBITS | SWP_NOMOVE)); } void WIN_ShowWindow(_THIS, SDL_Window * window) { + HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; + + ShowWindow(hwnd, SW_SHOW); } void WIN_HideWindow(_THIS, SDL_Window * window) { + HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; + + ShowWindow(hwnd, SW_HIDE); } void WIN_RaiseWindow(_THIS, SDL_Window * window) { + HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; + HWND top; + + if (window->flags & SDL_WINDOW_FULLSCREEN) { + top = HWND_TOPMOST; + } else { + top = HWND_NOTOPMOST; + } + SetWindowPos(hwnd, top, 0, 0, 0, 0, (SWP_NOMOVE | SWP_NOSIZE)); } void WIN_MaximizeWindow(_THIS, SDL_Window * window) { + HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; + + ShowWindow(hwnd, SW_MAXIMIZE); } void WIN_MinimizeWindow(_THIS, SDL_Window * window) { + HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; + + ShowWindow(hwnd, SW_MINIMIZE); } void WIN_RestoreWindow(_THIS, SDL_Window * window) { + HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; + + ShowWindow(hwnd, SW_RESTORE); } void WIN_SetWindowGrab(_THIS, SDL_Window * window) { + /* FIXME! */ } void WIN_DestroyWindow(_THIS, SDL_Window * window) { + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + + if (data) { + if (data->created) { + DestroyWindow(data->hwnd); + } + SDL_free(data); + } } SDL_bool WIN_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) { + HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; +/* FIXME! */ +#if 0 + if (info->version.major <= SDL_MAJOR_VERSION) { + info->window = hwnd; + /* FIXME! */ + info->hglrc = NULL; + return SDL_TRUE; + } else { + SDL_SetError("Application not compiled with SDL %d.%d\n", + SDL_MAJOR_VERSION, SDL_MINOR_VERSION); + return SDL_FALSE; + } +#endif } /* vi: set ts=4 sw=4 expandtab: */ diff -r ed4d4f1ea201 -r 5b9f50c957ed src/video/win32/SDL_win32window.h --- a/src/video/win32/SDL_win32window.h Tue Jun 27 07:46:36 2006 +0000 +++ b/src/video/win32/SDL_win32window.h Wed Jun 28 08:12:07 2006 +0000 @@ -27,6 +27,14 @@ #include "../SDL_sysvideo.h" #include "SDL_win32video.h" +typedef struct +{ + SDL_Window *window; + HWND hwnd; + WNDPROC wndproc; + BOOL created; +} SDL_WindowData; + extern int WIN_CreateWindow(_THIS, SDL_Window * window); extern int WIN_CreateWindowFrom(_THIS, SDL_Window * window, const void *data); extern void WIN_SetWindowTitle(_THIS, SDL_Window * window); diff -r ed4d4f1ea201 -r 5b9f50c957ed test/testwm2.c --- a/test/testwm2.c Tue Jun 27 07:46:36 2006 +0000 +++ b/test/testwm2.c Wed Jun 28 08:12:07 2006 +0000 @@ -64,10 +64,18 @@ } for (i = 0; i < num_windows; ++i) { char title[32]; + int x, y; SDL_snprintf(title, sizeof(title), "testwm %d", i + 1); + if (i == 0) { + x = SDL_WINDOWPOS_CENTERED; + y = SDL_WINDOWPOS_CENTERED; + } else { + x = SDL_WINDOWPOS_UNDEFINED; + y = SDL_WINDOWPOS_UNDEFINED; + } windows[i] = - SDL_CreateWindow(title, -1, -1, window_w, window_h, + SDL_CreateWindow(title, x, y, window_w, window_h, SDL_WINDOW_SHOWN); if (!windows[i]) { fprintf(stderr, "Couldn't create window: %s\n", SDL_GetError());