summaryrefslogtreecommitdiff
path: root/source/3rd-party/SDL2/src/video/windows/SDL_windowswindow.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/3rd-party/SDL2/src/video/windows/SDL_windowswindow.c')
-rw-r--r--source/3rd-party/SDL2/src/video/windows/SDL_windowswindow.c996
1 files changed, 996 insertions, 0 deletions
diff --git a/source/3rd-party/SDL2/src/video/windows/SDL_windowswindow.c b/source/3rd-party/SDL2/src/video/windows/SDL_windowswindow.c
new file mode 100644
index 0000000..45463c4
--- /dev/null
+++ b/source/3rd-party/SDL2/src/video/windows/SDL_windowswindow.c
@@ -0,0 +1,996 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_WINDOWS
+
+#include "../../core/windows/SDL_windows.h"
+
+#include "SDL_assert.h"
+#include "../SDL_sysvideo.h"
+#include "../SDL_pixels_c.h"
+#include "../../events/SDL_keyboard_c.h"
+#include "../../events/SDL_mouse_c.h"
+
+#include "SDL_windowsvideo.h"
+#include "SDL_windowswindow.h"
+#include "SDL_hints.h"
+
+/* Dropfile support */
+#include <shellapi.h>
+
+/* This is included after SDL_windowsvideo.h, which includes windows.h */
+#include "SDL_syswm.h"
+
+/* Windows CE compatibility */
+#ifndef SWP_NOCOPYBITS
+#define SWP_NOCOPYBITS 0
+#endif
+
+/* Fake window to help with DirectInput events. */
+HWND SDL_HelperWindow = NULL;
+static WCHAR *SDL_HelperWindowClassName = TEXT("SDLHelperWindowInputCatcher");
+static WCHAR *SDL_HelperWindowName = TEXT("SDLHelperWindowInputMsgWindow");
+static ATOM SDL_HelperWindowClass = 0;
+
+/* For borderless Windows, still want the following flags:
+ - WS_CAPTION: this seems to enable the Windows minimize animation
+ - WS_SYSMENU: enables system context menu on task bar
+ - WS_MINIMIZEBOX: window will respond to Windows minimize commands sent to all windows, such as windows key + m, shaking title bar, etc.
+ This will also cause the task bar to overlap the window and other windowed behaviors, so only use this for windows that shouldn't appear to be fullscreen
+ */
+
+#define STYLE_BASIC (WS_CLIPSIBLINGS | WS_CLIPCHILDREN)
+#define STYLE_FULLSCREEN (WS_POPUP)
+#define STYLE_BORDERLESS (WS_POPUP)
+#define STYLE_BORDERLESS_WINDOWED (WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX)
+#define STYLE_NORMAL (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX)
+#define STYLE_RESIZABLE (WS_THICKFRAME | WS_MAXIMIZEBOX)
+#define STYLE_MASK (STYLE_FULLSCREEN | STYLE_BORDERLESS | STYLE_NORMAL | STYLE_RESIZABLE)
+
+static DWORD
+GetWindowStyle(SDL_Window * window)
+{
+ DWORD style = 0;
+
+ if (window->flags & SDL_WINDOW_FULLSCREEN) {
+ style |= STYLE_FULLSCREEN;
+ } else {
+ if (window->flags & SDL_WINDOW_BORDERLESS) {
+ /* SDL 2.1:
+ This behavior more closely matches other platform where the window is borderless
+ but still interacts with the window manager (e.g. task bar shows above it, it can
+ be resized to fit within usable desktop area, etc.) so this should be the behavior
+ for a future SDL release.
+
+ If you want a borderless window the size of the desktop that looks like a fullscreen
+ window, then you should use the SDL_WINDOW_FULLSCREEN_DESKTOP flag.
+ */
+ if (SDL_GetHintBoolean("SDL_BORDERLESS_WINDOWED_STYLE", SDL_FALSE)) {
+ style |= STYLE_BORDERLESS_WINDOWED;
+ } else {
+ style |= STYLE_BORDERLESS;
+ }
+ } else {
+ style |= STYLE_NORMAL;
+ }
+
+ /* You can have a borderless resizable window */
+ if (window->flags & SDL_WINDOW_RESIZABLE) {
+ style |= STYLE_RESIZABLE;
+ }
+
+ /* Need to set initialize minimize style, or when we call ShowWindow with WS_MINIMIZE it will activate a random window */
+ if (window->flags & SDL_WINDOW_MINIMIZED) {
+ style |= WS_MINIMIZE;
+ }
+ }
+ return style;
+}
+
+static void
+WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x, int *y, int *width, int *height, SDL_bool use_current)
+{
+ RECT rect;
+
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = (use_current ? window->w : window->windowed.w);
+ rect.bottom = (use_current ? window->h : window->windowed.h);
+
+ /* borderless windows will have WM_NCCALCSIZE return 0 for the non-client area. When this happens, it looks like windows will send a resize message
+ expanding the window client area to the previous window + chrome size, so shouldn't need to adjust the window size for the set styles.
+ */
+ if (!(window->flags & SDL_WINDOW_BORDERLESS))
+ AdjustWindowRectEx(&rect, style, menu, 0);
+
+ *x = (use_current ? window->x : window->windowed.x) + rect.left;
+ *y = (use_current ? window->y : window->windowed.y) + rect.top;
+ *width = (rect.right - rect.left);
+ *height = (rect.bottom - rect.top);
+}
+
+static void
+WIN_AdjustWindowRect(SDL_Window *window, int *x, int *y, int *width, int *height, SDL_bool use_current)
+{
+ SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
+ HWND hwnd = data->hwnd;
+ DWORD style;
+ BOOL menu;
+
+ style = GetWindowLong(hwnd, GWL_STYLE);
+ menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
+ WIN_AdjustWindowRectWithStyle(window, style, menu, x, y, width, height, use_current);
+}
+
+static void
+WIN_SetWindowPositionInternal(_THIS, SDL_Window * window, UINT flags)
+{
+ SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
+ HWND hwnd = data->hwnd;
+ HWND top;
+ int x, y;
+ int w, h;
+
+ /* Figure out what the window area will be */
+ if (SDL_ShouldAllowTopmost() && ((window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS) || (window->flags & SDL_WINDOW_ALWAYS_ON_TOP))) {
+ top = HWND_TOPMOST;
+ } else {
+ top = HWND_NOTOPMOST;
+ }
+
+ WIN_AdjustWindowRect(window, &x, &y, &w, &h, SDL_TRUE);
+
+ data->expected_resize = SDL_TRUE;
+ SetWindowPos(hwnd, top, x, y, w, h, flags);
+ data->expected_resize = SDL_FALSE;
+}
+
+static int
+SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool created)
+{
+ SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
+ SDL_WindowData *data;
+
+ /* Allocate the window data */
+ data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
+ if (!data) {
+ return SDL_OutOfMemory();
+ }
+ data->window = window;
+ data->hwnd = hwnd;
+ data->parent = parent;
+ data->hdc = GetDC(hwnd);
+ data->hinstance = (HINSTANCE) GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
+ data->created = created;
+ data->mouse_button_flags = 0;
+ data->videodata = videodata;
+ data->initializing = SDL_TRUE;
+
+ window->driverdata = data;
+
+ /* Associate the data with the window */
+ if (!SetProp(hwnd, TEXT("SDL_WindowData"), data)) {
+ ReleaseDC(hwnd, data->hdc);
+ SDL_free(data);
+ return WIN_SetError("SetProp() failed");
+ }
+
+ /* Set up the window proc function */
+#ifdef GWLP_WNDPROC
+ data->wndproc = (WNDPROC) GetWindowLongPtr(hwnd, GWLP_WNDPROC);
+ if (data->wndproc == WIN_WindowProc) {
+ data->wndproc = NULL;
+ } else {
+ SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) WIN_WindowProc);
+ }
+#else
+ data->wndproc = (WNDPROC) GetWindowLong(hwnd, GWL_WNDPROC);
+ if (data->wndproc == WIN_WindowProc) {
+ data->wndproc = NULL;
+ } else {
+ SetWindowLong(hwnd, GWL_WNDPROC, (LONG_PTR) WIN_WindowProc);
+ }
+#endif
+
+ /* Fill in the SDL window with the window data */
+ {
+ RECT rect;
+ if (GetClientRect(hwnd, &rect)) {
+ int w = rect.right;
+ int h = rect.bottom;
+ if ((window->windowed.w && window->windowed.w != w) || (window->windowed.h && window->windowed.h != h)) {
+ /* We tried to create a window larger than the desktop and Windows didn't allow it. Override! */
+ int x, y;
+ /* Figure out what the window area will be */
+ WIN_AdjustWindowRect(window, &x, &y, &w, &h, SDL_FALSE);
+ SetWindowPos(hwnd, HWND_NOTOPMOST, x, y, w, h, SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE);
+ } else {
+ window->w = w;
+ window->h = h;
+ }
+ }
+ }
+ {
+ POINT point;
+ point.x = 0;
+ point.y = 0;
+ if (ClientToScreen(hwnd, &point)) {
+ window->x = point.x;
+ window->y = point.y;
+ }
+ }
+ {
+ DWORD style = GetWindowLong(hwnd, GWL_STYLE);
+ if (style & WS_VISIBLE) {
+ window->flags |= SDL_WINDOW_SHOWN;
+ } else {
+ window->flags &= ~SDL_WINDOW_SHOWN;
+ }
+ if (style & WS_POPUP) {
+ 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;
+ }
+#ifdef WS_MAXIMIZE
+ if (style & WS_MAXIMIZE) {
+ window->flags |= SDL_WINDOW_MAXIMIZED;
+ } else
+#endif
+ {
+ window->flags &= ~SDL_WINDOW_MAXIMIZED;
+ }
+#ifdef WS_MINIMIZE
+ if (style & WS_MINIMIZE) {
+ window->flags |= SDL_WINDOW_MINIMIZED;
+ } else
+#endif
+ {
+ window->flags &= ~SDL_WINDOW_MINIMIZED;
+ }
+ }
+ if (GetFocus() == hwnd) {
+ window->flags |= SDL_WINDOW_INPUT_FOCUS;
+ SDL_SetKeyboardFocus(data->window);
+
+ if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
+ RECT rect;
+ GetClientRect(hwnd, &rect);
+ ClientToScreen(hwnd, (LPPOINT) & rect);
+ ClientToScreen(hwnd, (LPPOINT) & rect + 1);
+ ClipCursor(&rect);
+ }
+ }
+
+ /* Enable multi-touch */
+ if (videodata->RegisterTouchWindow) {
+ videodata->RegisterTouchWindow(hwnd, (TWF_FINETOUCH|TWF_WANTPALM));
+ }
+
+ data->initializing = SDL_FALSE;
+
+ /* All done! */
+ return 0;
+}
+
+
+
+int
+WIN_CreateWindow(_THIS, SDL_Window * window)
+{
+ HWND hwnd, parent = NULL;
+ DWORD style = STYLE_BASIC;
+ int x, y;
+ int w, h;
+
+ if (window->flags & SDL_WINDOW_SKIP_TASKBAR) {
+ parent = CreateWindow(SDL_Appname, TEXT(""), STYLE_BASIC, 0, 0, 32, 32, NULL, NULL, SDL_Instance, NULL);
+ }
+
+ style |= GetWindowStyle(window);
+
+ /* Figure out what the window area will be */
+ WIN_AdjustWindowRectWithStyle(window, style, FALSE, &x, &y, &w, &h, SDL_FALSE);
+
+ hwnd =
+ CreateWindow(SDL_Appname, TEXT(""), style, x, y, w, h, parent, NULL,
+ SDL_Instance, NULL);
+ if (!hwnd) {
+ return WIN_SetError("Couldn't create window");
+ }
+
+ WIN_PumpEvents(_this);
+
+ if (SetupWindowData(_this, window, hwnd, parent, SDL_TRUE) < 0) {
+ DestroyWindow(hwnd);
+ if (parent) {
+ DestroyWindow(parent);
+ }
+ return -1;
+ }
+
+ /* Inform Windows of the frame change so we can respond to WM_NCCALCSIZE */
+ SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
+
+ if (window->flags & SDL_WINDOW_MINIMIZED) {
+ ShowWindow(hwnd, SW_SHOWMINNOACTIVE);
+ }
+
+ if (!(window->flags & SDL_WINDOW_OPENGL)) {
+ return 0;
+ }
+
+ /* The rest of this macro mess is for OpenGL or OpenGL ES windows */
+#if SDL_VIDEO_OPENGL_ES2
+ if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES
+#if SDL_VIDEO_OPENGL_WGL
+ && (!_this->gl_data || WIN_GL_UseEGL(_this))
+#endif /* SDL_VIDEO_OPENGL_WGL */
+ ) {
+#if SDL_VIDEO_OPENGL_EGL
+ if (WIN_GLES_SetupWindow(_this, window) < 0) {
+ WIN_DestroyWindow(_this, window);
+ return -1;
+ }
+ return 0;
+#else
+ return SDL_SetError("Could not create GLES window surface (EGL support not configured)");
+#endif /* SDL_VIDEO_OPENGL_EGL */
+ }
+#endif /* SDL_VIDEO_OPENGL_ES2 */
+
+#if SDL_VIDEO_OPENGL_WGL
+ if (WIN_GL_SetupWindow(_this, window) < 0) {
+ WIN_DestroyWindow(_this, window);
+ return -1;
+ }
+#else
+ return SDL_SetError("Could not create GL window (WGL support not configured)");
+#endif
+
+ 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(_this, window, hwnd, GetParent(hwnd), SDL_FALSE) < 0) {
+ return -1;
+ }
+
+#if SDL_VIDEO_OPENGL_WGL
+ {
+ const char *hint = SDL_GetHint(SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT);
+ if (hint) {
+ /* This hint is a pointer (in string form) of the address of
+ the window to share a pixel format with
+ */
+ SDL_Window *otherWindow = NULL;
+ SDL_sscanf(hint, "%p", (void**)&otherWindow);
+
+ /* Do some error checking on the pointer */
+ if (otherWindow != NULL && otherWindow->magic == &_this->window_magic) {
+ /* If the otherWindow has SDL_WINDOW_OPENGL set, set it for the new window as well */
+ if (otherWindow->flags & SDL_WINDOW_OPENGL) {
+ window->flags |= SDL_WINDOW_OPENGL;
+ if (!WIN_GL_SetPixelFormatFrom(_this, otherWindow, window)) {
+ return -1;
+ }
+ }
+ }
+ }
+ }
+#endif
+ return 0;
+}
+
+void
+WIN_SetWindowTitle(_THIS, SDL_Window * window)
+{
+ HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
+ LPTSTR title = WIN_UTF8ToString(window->title);
+ SetWindowText(hwnd, title);
+ SDL_free(title);
+}
+
+void
+WIN_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
+{
+ HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
+ HICON hicon = NULL;
+ BYTE *icon_bmp;
+ int icon_len, mask_len, y;
+ SDL_RWops *dst;
+
+ /* Create temporary buffer for ICONIMAGE structure */
+ mask_len = (icon->h * (icon->w + 7)/8);
+ icon_len = 40 + icon->h * icon->w * sizeof(Uint32) + mask_len;
+ icon_bmp = SDL_stack_alloc(BYTE, icon_len);
+ dst = SDL_RWFromMem(icon_bmp, icon_len);
+ if (!dst) {
+ SDL_stack_free(icon_bmp);
+ return;
+ }
+
+ /* Write the BITMAPINFO header */
+ SDL_WriteLE32(dst, 40);
+ SDL_WriteLE32(dst, icon->w);
+ SDL_WriteLE32(dst, icon->h * 2);
+ SDL_WriteLE16(dst, 1);
+ SDL_WriteLE16(dst, 32);
+ SDL_WriteLE32(dst, BI_RGB);
+ SDL_WriteLE32(dst, icon->h * icon->w * sizeof(Uint32));
+ SDL_WriteLE32(dst, 0);
+ SDL_WriteLE32(dst, 0);
+ SDL_WriteLE32(dst, 0);
+ SDL_WriteLE32(dst, 0);
+
+ /* Write the pixels upside down into the bitmap buffer */
+ SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888);
+ y = icon->h;
+ while (y--) {
+ Uint8 *src = (Uint8 *) icon->pixels + y * icon->pitch;
+ SDL_RWwrite(dst, src, icon->w * sizeof(Uint32), 1);
+ }
+
+ /* Write the mask */
+ SDL_memset(icon_bmp + icon_len - mask_len, 0xFF, mask_len);
+
+ hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
+
+ SDL_RWclose(dst);
+ SDL_stack_free(icon_bmp);
+
+ /* Set the icon for the window */
+ SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) hicon);
+
+ /* Set the icon in the task manager (should we do this?) */
+ SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) hicon);
+}
+
+void
+WIN_SetWindowPosition(_THIS, SDL_Window * window)
+{
+ WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE);
+}
+
+void
+WIN_SetWindowSize(_THIS, SDL_Window * window)
+{
+ WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOACTIVATE);
+}
+
+int
+WIN_GetWindowBordersSize(_THIS, SDL_Window * window, int *top, int *left, int *bottom, int *right)
+{
+ HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
+ RECT rcClient, rcWindow;
+ POINT ptDiff;
+
+ /* rcClient stores the size of the inner window, while rcWindow stores the outer size relative to the top-left
+ * screen position; so the top/left values of rcClient are always {0,0} and bottom/right are {height,width} */
+ GetClientRect(hwnd, &rcClient);
+ GetWindowRect(hwnd, &rcWindow);
+
+ /* convert the top/left values to make them relative to
+ * the window; they will end up being slightly negative */
+ ptDiff.y = rcWindow.top;
+ ptDiff.x = rcWindow.left;
+
+ ScreenToClient(hwnd, &ptDiff);
+
+ rcWindow.top = ptDiff.y;
+ rcWindow.left = ptDiff.x;
+
+ /* convert the bottom/right values to make them relative to the window,
+ * these will be slightly bigger than the inner width/height */
+ ptDiff.y = rcWindow.bottom;
+ ptDiff.x = rcWindow.right;
+
+ ScreenToClient(hwnd, &ptDiff);
+
+ rcWindow.bottom = ptDiff.y;
+ rcWindow.right = ptDiff.x;
+
+ /* Now that both the inner and outer rects use the same coordinate system we can substract them to get the border size.
+ * Keep in mind that the top/left coordinates of rcWindow are negative because the border lies slightly before {0,0},
+ * so switch them around because SDL2 wants them in positive. */
+ *top = rcClient.top - rcWindow.top;
+ *left = rcClient.left - rcWindow.left;
+ *bottom = rcWindow.bottom - rcClient.bottom;
+ *right = rcWindow.right - rcClient.right;
+
+ return 0;
+}
+
+void
+WIN_ShowWindow(_THIS, SDL_Window * window)
+{
+ DWORD style;
+ HWND hwnd;
+ int nCmdShow;
+
+ hwnd = ((SDL_WindowData *)window->driverdata)->hwnd;
+ nCmdShow = SW_SHOW;
+ style = GetWindowLong(hwnd, GWL_EXSTYLE);
+ if (style & WS_EX_NOACTIVATE) {
+ nCmdShow = SW_SHOWNOACTIVATE;
+ }
+ ShowWindow(hwnd, nCmdShow);
+}
+
+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;
+ SetForegroundWindow(hwnd);
+}
+
+void
+WIN_MaximizeWindow(_THIS, SDL_Window * window)
+{
+ SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
+ HWND hwnd = data->hwnd;
+ data->expected_resize = SDL_TRUE;
+ ShowWindow(hwnd, SW_MAXIMIZE);
+ data->expected_resize = SDL_FALSE;
+}
+
+void
+WIN_MinimizeWindow(_THIS, SDL_Window * window)
+{
+ HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
+ ShowWindow(hwnd, SW_MINIMIZE);
+}
+
+void
+WIN_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
+{
+ SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
+ HWND hwnd = data->hwnd;
+ DWORD style;
+
+ style = GetWindowLong(hwnd, GWL_STYLE);
+ style &= ~STYLE_MASK;
+ style |= GetWindowStyle(window);
+
+ data->in_border_change = SDL_TRUE;
+ SetWindowLong(hwnd, GWL_STYLE, style);
+ WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE);
+ data->in_border_change = SDL_FALSE;
+}
+
+void
+WIN_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable)
+{
+ SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
+ HWND hwnd = data->hwnd;
+ DWORD style;
+
+ style = GetWindowLong(hwnd, GWL_STYLE);
+ style &= ~STYLE_MASK;
+ style |= GetWindowStyle(window);
+
+ SetWindowLong(hwnd, GWL_STYLE, style);
+}
+
+void
+WIN_RestoreWindow(_THIS, SDL_Window * window)
+{
+ SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
+ HWND hwnd = data->hwnd;
+ data->expected_resize = SDL_TRUE;
+ ShowWindow(hwnd, SW_RESTORE);
+ data->expected_resize = SDL_FALSE;
+}
+
+void
+WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
+{
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ HWND hwnd = data->hwnd;
+ SDL_Rect bounds;
+ DWORD style;
+ HWND top;
+ int x, y;
+ int w, h;
+
+ if (SDL_ShouldAllowTopmost() && ((window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS) || window->flags & SDL_WINDOW_ALWAYS_ON_TOP)) {
+ top = HWND_TOPMOST;
+ } else {
+ top = HWND_NOTOPMOST;
+ }
+
+ style = GetWindowLong(hwnd, GWL_STYLE);
+ style &= ~STYLE_MASK;
+ style |= GetWindowStyle(window);
+
+ WIN_GetDisplayBounds(_this, display, &bounds);
+
+ if (fullscreen) {
+ x = bounds.x;
+ y = bounds.y;
+ w = bounds.w;
+ h = bounds.h;
+
+ /* Unset the maximized flag. This fixes
+ https://bugzilla.libsdl.org/show_bug.cgi?id=3215
+ */
+ if (style & WS_MAXIMIZE) {
+ data->windowed_mode_was_maximized = SDL_TRUE;
+ style &= ~WS_MAXIMIZE;
+ }
+ } else {
+ BOOL menu;
+
+ /* Restore window-maximization state, as applicable.
+ Special care is taken to *not* do this if and when we're
+ alt-tab'ing away (to some other window; as indicated by
+ in_window_deactivation), otherwise
+ https://bugzilla.libsdl.org/show_bug.cgi?id=3215 can reproduce!
+ */
+ if (data->windowed_mode_was_maximized && !data->in_window_deactivation) {
+ style |= WS_MAXIMIZE;
+ data->windowed_mode_was_maximized = SDL_FALSE;
+ }
+
+ menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
+ WIN_AdjustWindowRectWithStyle(window, style, menu, &x, &y, &w, &h, SDL_FALSE);
+ }
+ SetWindowLong(hwnd, GWL_STYLE, style);
+ data->expected_resize = SDL_TRUE;
+ SetWindowPos(hwnd, top, x, y, w, h, SWP_NOCOPYBITS | SWP_NOACTIVATE);
+ data->expected_resize = SDL_FALSE;
+}
+
+int
+WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
+{
+ SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
+ SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
+ HDC hdc;
+ BOOL succeeded = FALSE;
+
+ hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
+ if (hdc) {
+ succeeded = SetDeviceGammaRamp(hdc, (LPVOID)ramp);
+ if (!succeeded) {
+ WIN_SetError("SetDeviceGammaRamp()");
+ }
+ DeleteDC(hdc);
+ }
+ return succeeded ? 0 : -1;
+}
+
+int
+WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
+{
+ SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
+ SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
+ HDC hdc;
+ BOOL succeeded = FALSE;
+
+ hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
+ if (hdc) {
+ succeeded = GetDeviceGammaRamp(hdc, (LPVOID)ramp);
+ if (!succeeded) {
+ WIN_SetError("GetDeviceGammaRamp()");
+ }
+ DeleteDC(hdc);
+ }
+ return succeeded ? 0 : -1;
+}
+
+void
+WIN_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
+{
+ WIN_UpdateClipCursor(window);
+
+ if (window->flags & SDL_WINDOW_FULLSCREEN) {
+ UINT flags = SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE;
+
+ if (!(window->flags & SDL_WINDOW_SHOWN)) {
+ flags |= SWP_NOACTIVATE;
+ }
+ WIN_SetWindowPositionInternal(_this, window, flags);
+ }
+}
+
+void
+WIN_DestroyWindow(_THIS, SDL_Window * window)
+{
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+
+ if (data) {
+ ReleaseDC(data->hwnd, data->hdc);
+ RemoveProp(data->hwnd, TEXT("SDL_WindowData"));
+ if (data->created) {
+ DestroyWindow(data->hwnd);
+ if (data->parent) {
+ DestroyWindow(data->parent);
+ }
+ } else {
+ /* Restore any original event handler... */
+ if (data->wndproc != NULL) {
+#ifdef GWLP_WNDPROC
+ SetWindowLongPtr(data->hwnd, GWLP_WNDPROC,
+ (LONG_PTR) data->wndproc);
+#else
+ SetWindowLong(data->hwnd, GWL_WNDPROC,
+ (LONG_PTR) data->wndproc);
+#endif
+ }
+ }
+ SDL_free(data);
+ }
+ window->driverdata = NULL;
+}
+
+SDL_bool
+WIN_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
+{
+ const SDL_WindowData *data = (const SDL_WindowData *) window->driverdata;
+ if (info->version.major <= SDL_MAJOR_VERSION) {
+ int versionnum = SDL_VERSIONNUM(info->version.major, info->version.minor, info->version.patch);
+
+ info->subsystem = SDL_SYSWM_WINDOWS;
+ info->info.win.window = data->hwnd;
+
+ if (versionnum >= SDL_VERSIONNUM(2, 0, 4)) {
+ info->info.win.hdc = data->hdc;
+ }
+
+ if (versionnum >= SDL_VERSIONNUM(2, 0, 5)) {
+ info->info.win.hinstance = data->hinstance;
+ }
+
+ return SDL_TRUE;
+ } else {
+ SDL_SetError("Application not compiled with SDL %d.%d",
+ SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
+ return SDL_FALSE;
+ }
+}
+
+
+/*
+ * Creates a HelperWindow used for DirectInput events.
+ */
+int
+SDL_HelperWindowCreate(void)
+{
+ HINSTANCE hInstance = GetModuleHandle(NULL);
+ WNDCLASS wce;
+
+ /* Make sure window isn't created twice. */
+ if (SDL_HelperWindow != NULL) {
+ return 0;
+ }
+
+ /* Create the class. */
+ SDL_zero(wce);
+ wce.lpfnWndProc = DefWindowProc;
+ wce.lpszClassName = (LPCWSTR) SDL_HelperWindowClassName;
+ wce.hInstance = hInstance;
+
+ /* Register the class. */
+ SDL_HelperWindowClass = RegisterClass(&wce);
+ if (SDL_HelperWindowClass == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) {
+ return WIN_SetError("Unable to create Helper Window Class");
+ }
+
+ /* Create the window. */
+ SDL_HelperWindow = CreateWindowEx(0, SDL_HelperWindowClassName,
+ SDL_HelperWindowName,
+ WS_OVERLAPPED, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, HWND_MESSAGE, NULL,
+ hInstance, NULL);
+ if (SDL_HelperWindow == NULL) {
+ UnregisterClass(SDL_HelperWindowClassName, hInstance);
+ return WIN_SetError("Unable to create Helper Window");
+ }
+
+ return 0;
+}
+
+
+/*
+ * Destroys the HelperWindow previously created with SDL_HelperWindowCreate.
+ */
+void
+SDL_HelperWindowDestroy(void)
+{
+ HINSTANCE hInstance = GetModuleHandle(NULL);
+
+ /* Destroy the window. */
+ if (SDL_HelperWindow != NULL) {
+ if (DestroyWindow(SDL_HelperWindow) == 0) {
+ WIN_SetError("Unable to destroy Helper Window");
+ return;
+ }
+ SDL_HelperWindow = NULL;
+ }
+
+ /* Unregister the class. */
+ if (SDL_HelperWindowClass != 0) {
+ if ((UnregisterClass(SDL_HelperWindowClassName, hInstance)) == 0) {
+ WIN_SetError("Unable to destroy Helper Window Class");
+ return;
+ }
+ SDL_HelperWindowClass = 0;
+ }
+}
+
+void WIN_OnWindowEnter(_THIS, SDL_Window * window)
+{
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+
+ if (!data || !data->hwnd) {
+ /* The window wasn't fully initialized */
+ return;
+ }
+
+ if (window->flags & SDL_WINDOW_ALWAYS_ON_TOP) {
+ WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE);
+ }
+
+#ifdef WM_MOUSELEAVE
+ {
+ TRACKMOUSEEVENT trackMouseEvent;
+
+ trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
+ trackMouseEvent.dwFlags = TME_LEAVE;
+ trackMouseEvent.hwndTrack = data->hwnd;
+
+ TrackMouseEvent(&trackMouseEvent);
+ }
+#endif /* WM_MOUSELEAVE */
+}
+
+void
+WIN_UpdateClipCursor(SDL_Window *window)
+{
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ SDL_Mouse *mouse = SDL_GetMouse();
+ RECT rect;
+
+ if (data->in_title_click || data->focus_click_pending) {
+ return;
+ }
+ if (data->skip_update_clipcursor) {
+ data->skip_update_clipcursor = SDL_FALSE;
+ return;
+ }
+
+ if ((mouse->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
+ (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
+ if (mouse->relative_mode && !mouse->relative_mode_warp) {
+ LONG cx, cy;
+ GetWindowRect(data->hwnd, &rect);
+
+ cx = (rect.left + rect.right) / 2;
+ cy = (rect.top + rect.bottom) / 2;
+
+ /* Make an absurdly small clip rect */
+ rect.left = cx - 1;
+ rect.right = cx + 1;
+ rect.top = cy - 1;
+ rect.bottom = cy + 1;
+
+ if (ClipCursor(&rect)) {
+ data->cursor_clipped_rect = rect;
+ }
+ } else {
+ if (GetClientRect(data->hwnd, &rect) && !IsRectEmpty(&rect)) {
+ ClientToScreen(data->hwnd, (LPPOINT) & rect);
+ ClientToScreen(data->hwnd, (LPPOINT) & rect + 1);
+ if (ClipCursor(&rect)) {
+ data->cursor_clipped_rect = rect;
+ }
+ }
+ }
+ } else if (GetClipCursor(&rect) && SDL_memcmp(&rect, &data->cursor_clipped_rect, sizeof(rect)) == 0) {
+ ClipCursor(NULL);
+ SDL_zero(data->cursor_clipped_rect);
+ }
+}
+
+int
+WIN_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
+{
+ return 0; /* just succeed, the real work is done elsewhere. */
+}
+
+int
+WIN_SetWindowOpacity(_THIS, SDL_Window * window, float opacity)
+{
+ const SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ const HWND hwnd = data->hwnd;
+ const LONG style = GetWindowLong(hwnd, GWL_EXSTYLE);
+
+ SDL_assert(style != 0);
+
+ if (opacity == 1.0f) {
+ /* want it fully opaque, just mark it unlayered if necessary. */
+ if (style & WS_EX_LAYERED) {
+ if (SetWindowLong(hwnd, GWL_EXSTYLE, style & ~WS_EX_LAYERED) == 0) {
+ return WIN_SetError("SetWindowLong()");
+ }
+ }
+ } else {
+ const BYTE alpha = (BYTE) ((int) (opacity * 255.0f));
+ /* want it transparent, mark it layered if necessary. */
+ if ((style & WS_EX_LAYERED) == 0) {
+ if (SetWindowLong(hwnd, GWL_EXSTYLE, style | WS_EX_LAYERED) == 0) {
+ return WIN_SetError("SetWindowLong()");
+ }
+ }
+
+ if (SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA) == 0) {
+ return WIN_SetError("SetLayeredWindowAttributes()");
+ }
+ }
+
+ return 0;
+}
+
+void
+WIN_AcceptDragAndDrop(SDL_Window * window, SDL_bool accept)
+{
+ const SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ DragAcceptFiles(data->hwnd, accept ? TRUE : FALSE);
+}
+
+#endif /* SDL_VIDEO_DRIVER_WINDOWS */
+
+/* vi: set ts=4 sw=4 expandtab: */