diff options
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.c | 996 |
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: */ |