src/video/windows/SDL_windowswindow.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 23 Dec 2013 17:55:06 -0800
changeset 8072 9d8865351afd
parent 8021 f96e12e0ade9
child 8093 b43765095a6f
permissions -rw-r--r--
Setting the mouse in relative mode implies grabbing the mouse.
This fixes getting mouse button events in raw input relative mode on X11.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #if SDL_VIDEO_DRIVER_WINDOWS
    24 
    25 #include "../../core/windows/SDL_windows.h"
    26 
    27 #include "SDL_assert.h"
    28 #include "../SDL_sysvideo.h"
    29 #include "../SDL_pixels_c.h"
    30 #include "../../events/SDL_keyboard_c.h"
    31 #include "../../events/SDL_mouse_c.h"
    32 
    33 #include "SDL_windowsvideo.h"
    34 #include "SDL_windowswindow.h"
    35 
    36 /* Dropfile support */
    37 #include <shellapi.h>
    38 
    39 /* This is included after SDL_windowsvideo.h, which includes windows.h */
    40 #include "SDL_syswm.h"
    41 
    42 /* Windows CE compatibility */
    43 #ifndef SWP_NOCOPYBITS
    44 #define SWP_NOCOPYBITS 0
    45 #endif
    46 
    47 /* Fake window to help with DirectInput events. */
    48 HWND SDL_HelperWindow = NULL;
    49 static WCHAR *SDL_HelperWindowClassName = TEXT("SDLHelperWindowInputCatcher");
    50 static WCHAR *SDL_HelperWindowName = TEXT("SDLHelperWindowInputMsgWindow");
    51 static ATOM SDL_HelperWindowClass = 0;
    52 
    53 #define STYLE_BASIC         (WS_CLIPSIBLINGS | WS_CLIPCHILDREN)
    54 #define STYLE_FULLSCREEN    (WS_POPUP)
    55 #define STYLE_BORDERLESS    (WS_POPUP)
    56 #define STYLE_NORMAL        (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX)
    57 #define STYLE_RESIZABLE     (WS_THICKFRAME | WS_MAXIMIZEBOX)
    58 #define STYLE_MASK          (STYLE_FULLSCREEN | STYLE_BORDERLESS | STYLE_NORMAL | STYLE_RESIZABLE)
    59 
    60 static DWORD
    61 GetWindowStyle(SDL_Window * window)
    62 {
    63     DWORD style = 0;
    64 
    65     if (window->flags & SDL_WINDOW_FULLSCREEN) {
    66         style |= STYLE_FULLSCREEN;
    67     } else {
    68         if (window->flags & SDL_WINDOW_BORDERLESS) {
    69             style |= STYLE_BORDERLESS;
    70         } else {
    71             style |= STYLE_NORMAL;
    72         }
    73         if (window->flags & SDL_WINDOW_RESIZABLE) {
    74             style |= STYLE_RESIZABLE;
    75         }
    76     }
    77     return style;
    78 }
    79 
    80 static void
    81 WIN_SetWindowPositionInternal(_THIS, SDL_Window * window, UINT flags)
    82 {
    83     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
    84     HWND hwnd = data->hwnd;
    85     RECT rect;
    86     DWORD style;
    87     HWND top;
    88     BOOL menu;
    89     int x, y;
    90     int w, h;
    91 
    92     /* Figure out what the window area will be */
    93     if (SDL_ShouldAllowTopmost() && (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) {
    94         top = HWND_TOPMOST;
    95     } else {
    96         top = HWND_NOTOPMOST;
    97     }
    98     style = GetWindowLong(hwnd, GWL_STYLE);
    99     rect.left = 0;
   100     rect.top = 0;
   101     rect.right = window->w;
   102     rect.bottom = window->h;
   103     menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
   104     AdjustWindowRectEx(&rect, style, menu, 0);
   105     w = (rect.right - rect.left);
   106     h = (rect.bottom - rect.top);
   107     x = window->x + rect.left;
   108     y = window->y + rect.top;
   109 
   110     data->expected_resize = TRUE;
   111     SetWindowPos(hwnd, top, x, y, w, h, flags);
   112     data->expected_resize = FALSE;
   113 }
   114 
   115 static int
   116 SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, SDL_bool created)
   117 {
   118     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   119     SDL_WindowData *data;
   120 
   121     /* Allocate the window data */
   122     data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
   123     if (!data) {
   124         return SDL_OutOfMemory();
   125     }
   126     data->window = window;
   127     data->hwnd = hwnd;
   128     data->hdc = GetDC(hwnd);
   129     data->created = created;
   130     data->mouse_button_flags = 0;
   131     data->videodata = videodata;
   132 
   133     window->driverdata = data;
   134 
   135     /* Associate the data with the window */
   136     if (!SetProp(hwnd, TEXT("SDL_WindowData"), data)) {
   137         ReleaseDC(hwnd, data->hdc);
   138         SDL_free(data);
   139         return WIN_SetError("SetProp() failed");
   140     }
   141 
   142     /* Set up the window proc function */
   143 #ifdef GWLP_WNDPROC
   144     data->wndproc = (WNDPROC) GetWindowLongPtr(hwnd, GWLP_WNDPROC);
   145     if (data->wndproc == WIN_WindowProc) {
   146         data->wndproc = NULL;
   147     } else {
   148         SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) WIN_WindowProc);
   149     }
   150 #else
   151     data->wndproc = (WNDPROC) GetWindowLong(hwnd, GWL_WNDPROC);
   152     if (data->wndproc == WIN_WindowProc) {
   153         data->wndproc = NULL;
   154     } else {
   155         SetWindowLong(hwnd, GWL_WNDPROC, (LONG_PTR) WIN_WindowProc);
   156     }
   157 #endif
   158 
   159     /* Fill in the SDL window with the window data */
   160     {
   161         RECT rect;
   162         if (GetClientRect(hwnd, &rect)) {
   163             int w = rect.right;
   164             int h = rect.bottom;
   165             if ((window->w && window->w != w) || (window->h && window->h != h)) {
   166                 /* We tried to create a window larger than the desktop and Windows didn't allow it.  Override! */
   167                 WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE);
   168             } else {
   169                 window->w = w;
   170                 window->h = h;
   171             }
   172         }
   173     }
   174     {
   175         POINT point;
   176         point.x = 0;
   177         point.y = 0;
   178         if (ClientToScreen(hwnd, &point)) {
   179             window->x = point.x;
   180             window->y = point.y;
   181         }
   182     }
   183     {
   184         DWORD style = GetWindowLong(hwnd, GWL_STYLE);
   185         if (style & WS_VISIBLE) {
   186             window->flags |= SDL_WINDOW_SHOWN;
   187         } else {
   188             window->flags &= ~SDL_WINDOW_SHOWN;
   189         }
   190         if (style & (WS_BORDER | WS_THICKFRAME)) {
   191             window->flags &= ~SDL_WINDOW_BORDERLESS;
   192         } else {
   193             window->flags |= SDL_WINDOW_BORDERLESS;
   194         }
   195         if (style & WS_THICKFRAME) {
   196             window->flags |= SDL_WINDOW_RESIZABLE;
   197         } else {
   198             window->flags &= ~SDL_WINDOW_RESIZABLE;
   199         }
   200 #ifdef WS_MAXIMIZE
   201         if (style & WS_MAXIMIZE) {
   202             window->flags |= SDL_WINDOW_MAXIMIZED;
   203         } else
   204 #endif
   205         {
   206             window->flags &= ~SDL_WINDOW_MAXIMIZED;
   207         }
   208 #ifdef WS_MINIMIZE
   209         if (style & WS_MINIMIZE) {
   210             window->flags |= SDL_WINDOW_MINIMIZED;
   211         } else
   212 #endif
   213         {
   214             window->flags &= ~SDL_WINDOW_MINIMIZED;
   215         }
   216     }
   217     if (GetFocus() == hwnd) {
   218         window->flags |= SDL_WINDOW_INPUT_FOCUS;
   219         SDL_SetKeyboardFocus(data->window);
   220 
   221         if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   222             RECT rect;
   223             GetClientRect(hwnd, &rect);
   224             ClientToScreen(hwnd, (LPPOINT) & rect);
   225             ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   226             ClipCursor(&rect);
   227         }
   228     }
   229 
   230     /* Enable multi-touch */
   231     if (videodata->RegisterTouchWindow) {
   232         videodata->RegisterTouchWindow(hwnd, (TWF_FINETOUCH|TWF_WANTPALM));
   233     }
   234 
   235     /* Enable dropping files */
   236     DragAcceptFiles(hwnd, TRUE);
   237 
   238     /* All done! */
   239     return 0;
   240 }
   241 
   242 int
   243 WIN_CreateWindow(_THIS, SDL_Window * window)
   244 {
   245     HWND hwnd;
   246     RECT rect;
   247     DWORD style = STYLE_BASIC;
   248     int x, y;
   249     int w, h;
   250 
   251     style |= GetWindowStyle(window);
   252 
   253     /* Figure out what the window area will be */
   254     rect.left = window->x;
   255     rect.top = window->y;
   256     rect.right = window->x + window->w;
   257     rect.bottom = window->y + window->h;
   258     AdjustWindowRectEx(&rect, style, FALSE, 0);
   259     x = rect.left;
   260     y = rect.top;
   261     w = (rect.right - rect.left);
   262     h = (rect.bottom - rect.top);
   263 
   264     hwnd =
   265         CreateWindow(SDL_Appname, TEXT(""), style, x, y, w, h, NULL, NULL,
   266                      SDL_Instance, NULL);
   267     if (!hwnd) {
   268         return WIN_SetError("Couldn't create window");
   269     }
   270 
   271     WIN_PumpEvents(_this);
   272 
   273     if (SetupWindowData(_this, window, hwnd, SDL_TRUE) < 0) {
   274         DestroyWindow(hwnd);
   275         return -1;
   276     }
   277 
   278 #if SDL_VIDEO_OPENGL_WGL
   279     /* We need to initialize the extensions before deciding how to create ES profiles */
   280     if (window->flags & SDL_WINDOW_OPENGL) {
   281         WIN_GL_InitExtensions(_this);
   282     }
   283 #endif
   284 
   285 #if SDL_VIDEO_OPENGL_ES2
   286     if ((window->flags & SDL_WINDOW_OPENGL) &&
   287         _this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES
   288 #if SDL_VIDEO_OPENGL_WGL           
   289         && (!_this->gl_data || !_this->gl_data->HAS_WGL_EXT_create_context_es2_profile)
   290 #endif  
   291         ) {
   292 #if SDL_VIDEO_OPENGL_EGL  
   293         if (WIN_GLES_SetupWindow(_this, window) < 0) {
   294             WIN_DestroyWindow(_this, window);
   295             return -1;
   296         }
   297 #else
   298         return SDL_SetError("Could not create GLES window surface (no EGL support available)");
   299 #endif /* SDL_VIDEO_OPENGL_EGL */
   300     } else 
   301 #endif /* SDL_VIDEO_OPENGL_ES2 */
   302 
   303 #if SDL_VIDEO_OPENGL_WGL
   304     if (window->flags & SDL_WINDOW_OPENGL) {
   305         if (WIN_GL_SetupWindow(_this, window) < 0) {
   306             WIN_DestroyWindow(_this, window);
   307             return -1;
   308         }
   309     }
   310 #endif
   311 
   312     return 0;
   313 }
   314 
   315 int
   316 WIN_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   317 {
   318     HWND hwnd = (HWND) data;
   319     LPTSTR title;
   320     int titleLen;
   321 
   322     /* Query the title from the existing window */
   323     titleLen = GetWindowTextLength(hwnd);
   324     title = SDL_stack_alloc(TCHAR, titleLen + 1);
   325     if (title) {
   326         titleLen = GetWindowText(hwnd, title, titleLen);
   327     } else {
   328         titleLen = 0;
   329     }
   330     if (titleLen > 0) {
   331         window->title = WIN_StringToUTF8(title);
   332     }
   333     if (title) {
   334         SDL_stack_free(title);
   335     }
   336 
   337     if (SetupWindowData(_this, window, hwnd, SDL_FALSE) < 0) {
   338         return -1;
   339     }
   340     return 0;
   341 }
   342 
   343 void
   344 WIN_SetWindowTitle(_THIS, SDL_Window * window)
   345 {
   346     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   347     LPTSTR title;
   348 
   349     if (window->title) {
   350         title = WIN_UTF8ToString(window->title);
   351     } else {
   352         title = NULL;
   353     }
   354     SetWindowText(hwnd, title ? title : TEXT(""));
   355     SDL_free(title);
   356 }
   357 
   358 void
   359 WIN_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   360 {
   361     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   362     HICON hicon = NULL;
   363     BYTE *icon_bmp;
   364     int icon_len, y;
   365     SDL_RWops *dst;
   366 
   367     /* Create temporary bitmap buffer */
   368     icon_len = 40 + icon->h * icon->w * 4;
   369     icon_bmp = SDL_stack_alloc(BYTE, icon_len);
   370     dst = SDL_RWFromMem(icon_bmp, icon_len);
   371     if (!dst) {
   372         SDL_stack_free(icon_bmp);
   373         return;
   374     }
   375 
   376     /* Write the BITMAPINFO header */
   377     SDL_WriteLE32(dst, 40);
   378     SDL_WriteLE32(dst, icon->w);
   379     SDL_WriteLE32(dst, icon->h * 2);
   380     SDL_WriteLE16(dst, 1);
   381     SDL_WriteLE16(dst, 32);
   382     SDL_WriteLE32(dst, BI_RGB);
   383     SDL_WriteLE32(dst, icon->h * icon->w * 4);
   384     SDL_WriteLE32(dst, 0);
   385     SDL_WriteLE32(dst, 0);
   386     SDL_WriteLE32(dst, 0);
   387     SDL_WriteLE32(dst, 0);
   388 
   389     /* Write the pixels upside down into the bitmap buffer */
   390     SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888);
   391     y = icon->h;
   392     while (y--) {
   393         Uint8 *src = (Uint8 *) icon->pixels + y * icon->pitch;
   394         SDL_RWwrite(dst, src, icon->pitch, 1);
   395     }
   396 
   397     hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
   398 
   399     SDL_RWclose(dst);
   400     SDL_stack_free(icon_bmp);
   401 
   402     /* Set the icon for the window */
   403     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) hicon);
   404 
   405     /* Set the icon in the task manager (should we do this?) */
   406     SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) hicon);
   407 }
   408 
   409 void
   410 WIN_SetWindowPosition(_THIS, SDL_Window * window)
   411 {
   412     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE);
   413 }
   414 
   415 void
   416 WIN_SetWindowSize(_THIS, SDL_Window * window)
   417 {
   418     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOACTIVATE);
   419 }
   420 
   421 void
   422 WIN_ShowWindow(_THIS, SDL_Window * window)
   423 {
   424     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   425     ShowWindow(hwnd, SW_SHOW);
   426 }
   427 
   428 void
   429 WIN_HideWindow(_THIS, SDL_Window * window)
   430 {
   431     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   432     ShowWindow(hwnd, SW_HIDE);
   433 }
   434 
   435 void
   436 WIN_RaiseWindow(_THIS, SDL_Window * window)
   437 {
   438     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE);
   439 }
   440 
   441 void
   442 WIN_MaximizeWindow(_THIS, SDL_Window * window)
   443 {
   444     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   445     HWND hwnd = data->hwnd;
   446     data->expected_resize = TRUE;
   447     ShowWindow(hwnd, SW_MAXIMIZE);
   448     data->expected_resize = FALSE;
   449 }
   450 
   451 void
   452 WIN_MinimizeWindow(_THIS, SDL_Window * window)
   453 {
   454     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   455     ShowWindow(hwnd, SW_MINIMIZE);
   456 }
   457 
   458 void
   459 WIN_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
   460 {
   461     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   462     DWORD style = GetWindowLong(hwnd, GWL_STYLE);
   463 
   464     if (bordered) {
   465         style &= ~STYLE_BORDERLESS;
   466         style |= STYLE_NORMAL;
   467     } else {
   468         style &= ~STYLE_NORMAL;
   469         style |= STYLE_BORDERLESS;
   470     }
   471 
   472     SetWindowLong(hwnd, GWL_STYLE, style);
   473     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_FRAMECHANGED | SWP_NOREPOSITION | SWP_NOZORDER |SWP_NOACTIVATE | SWP_NOSENDCHANGING);
   474 }
   475 
   476 void
   477 WIN_RestoreWindow(_THIS, SDL_Window * window)
   478 {
   479     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   480     HWND hwnd = data->hwnd;
   481     data->expected_resize = TRUE;
   482     ShowWindow(hwnd, SW_RESTORE);
   483     data->expected_resize = FALSE;
   484 }
   485 
   486 void
   487 WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   488 {
   489     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   490     HWND hwnd = data->hwnd;
   491     RECT rect;
   492     SDL_Rect bounds;
   493     DWORD style;
   494     HWND top;
   495     BOOL menu;
   496     int x, y;
   497     int w, h;
   498 
   499     if (SDL_ShouldAllowTopmost() && (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) {
   500         top = HWND_TOPMOST;
   501     } else {
   502         top = HWND_NOTOPMOST;
   503     }
   504 
   505     style = GetWindowLong(hwnd, GWL_STYLE);
   506     style &= ~STYLE_MASK;
   507     style |= GetWindowStyle(window);
   508 
   509     WIN_GetDisplayBounds(_this, display, &bounds);
   510 
   511     if (fullscreen) {
   512         x = bounds.x;
   513         y = bounds.y;
   514         w = bounds.w;
   515         h = bounds.h;
   516     } else {
   517         rect.left = 0;
   518         rect.top = 0;
   519         rect.right = window->windowed.w;
   520         rect.bottom = window->windowed.h;
   521         menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
   522         AdjustWindowRectEx(&rect, style, menu, 0);
   523         w = (rect.right - rect.left);
   524         h = (rect.bottom - rect.top);
   525         x = window->windowed.x + rect.left;
   526         y = window->windowed.y + rect.top;
   527     }
   528     SetWindowLong(hwnd, GWL_STYLE, style);
   529     data->expected_resize = TRUE;
   530     SetWindowPos(hwnd, top, x, y, w, h, SWP_NOCOPYBITS);
   531     data->expected_resize = FALSE;
   532 }
   533 
   534 int
   535 WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
   536 {
   537     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   538     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
   539     HDC hdc;
   540     BOOL succeeded = FALSE;
   541 
   542     hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
   543     if (hdc) {
   544         succeeded = SetDeviceGammaRamp(hdc, (LPVOID)ramp);
   545         if (!succeeded) {
   546             WIN_SetError("SetDeviceGammaRamp()");
   547         }
   548         DeleteDC(hdc);
   549     }
   550     return succeeded ? 0 : -1;
   551 }
   552 
   553 int
   554 WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
   555 {
   556     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   557     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
   558     HDC hdc;
   559     BOOL succeeded = FALSE;
   560 
   561     hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
   562     if (hdc) {
   563         succeeded = GetDeviceGammaRamp(hdc, (LPVOID)ramp);
   564         if (!succeeded) {
   565             WIN_SetError("GetDeviceGammaRamp()");
   566         }
   567         DeleteDC(hdc);
   568     }
   569     return succeeded ? 0 : -1;
   570 }
   571 
   572 void
   573 WIN_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
   574 {
   575     WIN_UpdateClipCursor(window);
   576 
   577     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   578         UINT flags = SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE;
   579 
   580         if (!(window->flags & SDL_WINDOW_SHOWN)) {
   581             flags |= SWP_NOACTIVATE;
   582         }
   583         WIN_SetWindowPositionInternal(_this, window, flags);
   584     }
   585 }
   586 
   587 void
   588 WIN_DestroyWindow(_THIS, SDL_Window * window)
   589 {
   590     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   591 
   592     if (data) {
   593         ReleaseDC(data->hwnd, data->hdc);
   594         if (data->created) {
   595             DestroyWindow(data->hwnd);
   596         } else {
   597             /* Restore any original event handler... */
   598             if (data->wndproc != NULL) {
   599 #ifdef GWLP_WNDPROC
   600                 SetWindowLongPtr(data->hwnd, GWLP_WNDPROC,
   601                                  (LONG_PTR) data->wndproc);
   602 #else
   603                 SetWindowLong(data->hwnd, GWL_WNDPROC,
   604                               (LONG_PTR) data->wndproc);
   605 #endif
   606             }
   607         }
   608         SDL_free(data);
   609     }
   610 }
   611 
   612 SDL_bool
   613 WIN_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   614 {
   615     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   616     if (info->version.major <= SDL_MAJOR_VERSION) {
   617         info->subsystem = SDL_SYSWM_WINDOWS;
   618         info->info.win.window = hwnd;
   619         return SDL_TRUE;
   620     } else {
   621         SDL_SetError("Application not compiled with SDL %d.%d\n",
   622                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   623         return SDL_FALSE;
   624     }
   625 }
   626 
   627 
   628 /*
   629  * Creates a HelperWindow used for DirectInput events.
   630  */
   631 int
   632 SDL_HelperWindowCreate(void)
   633 {
   634     HINSTANCE hInstance = GetModuleHandle(NULL);
   635     WNDCLASS wce;
   636 
   637     /* Make sure window isn't created twice. */
   638     if (SDL_HelperWindow != NULL) {
   639         return 0;
   640     }
   641 
   642     /* Create the class. */
   643     SDL_zero(wce);
   644     wce.lpfnWndProc = DefWindowProc;
   645     wce.lpszClassName = (LPCWSTR) SDL_HelperWindowClassName;
   646     wce.hInstance = hInstance;
   647 
   648     /* Register the class. */
   649     SDL_HelperWindowClass = RegisterClass(&wce);
   650     if (SDL_HelperWindowClass == 0) {
   651         return WIN_SetError("Unable to create Helper Window Class");
   652     }
   653 
   654     /* Create the window. */
   655     SDL_HelperWindow = CreateWindowEx(0, SDL_HelperWindowClassName,
   656                                       SDL_HelperWindowName,
   657                                       WS_OVERLAPPED, CW_USEDEFAULT,
   658                                       CW_USEDEFAULT, CW_USEDEFAULT,
   659                                       CW_USEDEFAULT, HWND_MESSAGE, NULL,
   660                                       hInstance, NULL);
   661     if (SDL_HelperWindow == NULL) {
   662         UnregisterClass(SDL_HelperWindowClassName, hInstance);
   663         return WIN_SetError("Unable to create Helper Window");
   664     }
   665 
   666     return 0;
   667 }
   668 
   669 
   670 /*
   671  * Destroys the HelperWindow previously created with SDL_HelperWindowCreate.
   672  */
   673 void
   674 SDL_HelperWindowDestroy(void)
   675 {
   676     HINSTANCE hInstance = GetModuleHandle(NULL);
   677 
   678     /* Destroy the window. */
   679     if (SDL_HelperWindow != NULL) {
   680         if (DestroyWindow(SDL_HelperWindow) == 0) {
   681             WIN_SetError("Unable to destroy Helper Window");
   682             return;
   683         }
   684         SDL_HelperWindow = NULL;
   685     }
   686 
   687     /* Unregister the class. */
   688     if (SDL_HelperWindowClass != 0) {
   689         if ((UnregisterClass(SDL_HelperWindowClassName, hInstance)) == 0) {
   690             WIN_SetError("Unable to destroy Helper Window Class");
   691             return;
   692         }
   693         SDL_HelperWindowClass = 0;
   694     }
   695 }
   696 
   697 void WIN_OnWindowEnter(_THIS, SDL_Window * window)
   698 {
   699 #ifdef WM_MOUSELEAVE
   700     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   701     TRACKMOUSEEVENT trackMouseEvent;
   702 
   703     if (!data || !data->hwnd) {
   704         /* The window wasn't fully initialized */
   705         return;
   706     }
   707 
   708     trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
   709     trackMouseEvent.dwFlags = TME_LEAVE;
   710     trackMouseEvent.hwndTrack = data->hwnd;
   711 
   712     TrackMouseEvent(&trackMouseEvent);
   713 #endif /* WM_MOUSELEAVE */
   714 }
   715 
   716 void
   717 WIN_UpdateClipCursor(SDL_Window *window)
   718 {
   719     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   720     SDL_Mouse *mouse = SDL_GetMouse();
   721 
   722     /* Don't clip the cursor while we're in the modal resize or move loop */
   723     if (data->in_modal_loop) {
   724         ClipCursor(NULL);
   725         return;
   726     }
   727 
   728     if ((mouse->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
   729         (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
   730         if (mouse->relative_mode && !mouse->relative_mode_warp) {
   731             LONG cx, cy;
   732             RECT rect;
   733             GetWindowRect(data->hwnd, &rect);
   734 
   735             cx = (rect.left + rect.right) / 2;
   736             cy = (rect.top + rect.bottom) / 2;
   737 
   738             /* Make an absurdly small clip rect */
   739             rect.left = cx - 1;
   740             rect.right = cx + 1;
   741             rect.top = cy - 1;
   742             rect.bottom = cy + 1;
   743 
   744             ClipCursor(&rect);
   745         } else {
   746             RECT rect;
   747             if (GetClientRect(data->hwnd, &rect) && !IsRectEmpty(&rect)) {
   748                 ClientToScreen(data->hwnd, (LPPOINT) & rect);
   749                 ClientToScreen(data->hwnd, (LPPOINT) & rect + 1);
   750                 ClipCursor(&rect);
   751             }
   752         }
   753     } else {
   754         ClipCursor(NULL);
   755     }
   756 }
   757 
   758 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   759 
   760 /* vi: set ts=4 sw=4 expandtab: */