• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2016 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_internal.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 #include "SDL_hints.h"
36 
37 /* Dropfile support */
38 #include <shellapi.h>
39 
40 /* This is included after SDL_windowsvideo.h, which includes windows.h */
41 #include "SDL_syswm.h"
42 
43 /* Windows CE compatibility */
44 #ifndef SWP_NOCOPYBITS
45 #define SWP_NOCOPYBITS 0
46 #endif
47 
48 /* Fake window to help with DirectInput events. */
49 HWND SDL_HelperWindow = NULL;
50 static WCHAR *SDL_HelperWindowClassName = TEXT("SDLHelperWindowInputCatcher");
51 static WCHAR *SDL_HelperWindowName = TEXT("SDLHelperWindowInputMsgWindow");
52 static ATOM SDL_HelperWindowClass = 0;
53 
54 #define STYLE_BASIC         (WS_CLIPSIBLINGS | WS_CLIPCHILDREN)
55 #define STYLE_FULLSCREEN    (WS_POPUP)
56 #define STYLE_BORDERLESS    (WS_POPUP)
57 #define STYLE_NORMAL        (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX)
58 #define STYLE_RESIZABLE     (WS_THICKFRAME | WS_MAXIMIZEBOX)
59 #define STYLE_MASK          (STYLE_FULLSCREEN | STYLE_BORDERLESS | STYLE_NORMAL | STYLE_RESIZABLE)
60 
61 static DWORD
GetWindowStyle(SDL_Window * window)62 GetWindowStyle(SDL_Window * window)
63 {
64     DWORD style = 0;
65 
66     if (window->flags & SDL_WINDOW_FULLSCREEN) {
67         style |= STYLE_FULLSCREEN;
68     } else {
69         if (window->flags & SDL_WINDOW_BORDERLESS) {
70             style |= STYLE_BORDERLESS;
71         } else {
72             style |= STYLE_NORMAL;
73         }
74         if (window->flags & SDL_WINDOW_RESIZABLE) {
75             style |= STYLE_RESIZABLE;
76         }
77     }
78     return style;
79 }
80 
81 static void
WIN_SetWindowPositionInternal(_THIS,SDL_Window * window,UINT flags)82 WIN_SetWindowPositionInternal(_THIS, SDL_Window * window, UINT flags)
83 {
84     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
85     HWND hwnd = data->hwnd;
86     RECT rect;
87     DWORD style;
88     HWND top;
89     BOOL menu;
90     int x, y;
91     int w, h;
92 
93     /* Figure out what the window area will be */
94     if (SDL_ShouldAllowTopmost() && (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) {
95         top = HWND_TOPMOST;
96     } else {
97         top = HWND_NOTOPMOST;
98     }
99     style = GetWindowLong(hwnd, GWL_STYLE);
100     rect.left = 0;
101     rect.top = 0;
102     rect.right = window->w;
103     rect.bottom = window->h;
104     menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
105     AdjustWindowRectEx(&rect, style, menu, 0);
106     w = (rect.right - rect.left);
107     h = (rect.bottom - rect.top);
108     x = window->x + rect.left;
109     y = window->y + rect.top;
110 
111     data->expected_resize = SDL_TRUE;
112     SetWindowPos(hwnd, top, x, y, w, h, flags);
113     data->expected_resize = SDL_FALSE;
114 }
115 
116 static int
SetupWindowData(_THIS,SDL_Window * window,HWND hwnd,SDL_bool created)117 SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, SDL_bool created)
118 {
119     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
120     SDL_WindowData *data;
121 
122     /* Allocate the window data */
123     data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
124     if (!data) {
125         return SDL_OutOfMemory();
126     }
127     data->window = window;
128     data->hwnd = hwnd;
129     data->hdc = GetDC(hwnd);
130     data->created = created;
131     data->mouse_button_flags = 0;
132     data->videodata = videodata;
133     data->initializing = SDL_TRUE;
134 
135     window->driverdata = data;
136 
137     /* Associate the data with the window */
138     if (!SetProp(hwnd, TEXT("SDL_WindowData"), data)) {
139         ReleaseDC(hwnd, data->hdc);
140         SDL_free(data);
141         return WIN_SetError("SetProp() failed");
142     }
143 
144     /* Set up the window proc function */
145 #ifdef GWLP_WNDPROC
146     data->wndproc = (WNDPROC) GetWindowLongPtr(hwnd, GWLP_WNDPROC);
147     if (data->wndproc == WIN_WindowProc) {
148         data->wndproc = NULL;
149     } else {
150         SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) WIN_WindowProc);
151     }
152 #else
153     data->wndproc = (WNDPROC) GetWindowLong(hwnd, GWL_WNDPROC);
154     if (data->wndproc == WIN_WindowProc) {
155         data->wndproc = NULL;
156     } else {
157         SetWindowLong(hwnd, GWL_WNDPROC, (LONG_PTR) WIN_WindowProc);
158     }
159 #endif
160 
161     /* Fill in the SDL window with the window data */
162     {
163         RECT rect;
164         if (GetClientRect(hwnd, &rect)) {
165             int w = rect.right;
166             int h = rect.bottom;
167             if ((window->w && window->w != w) || (window->h && window->h != h)) {
168                 /* We tried to create a window larger than the desktop and Windows didn't allow it.  Override! */
169                 RECT rect;
170                 DWORD style;
171                 BOOL menu;
172                 int x, y;
173                 int w, h;
174 
175                 /* Figure out what the window area will be */
176                 style = GetWindowLong(hwnd, GWL_STYLE);
177                 rect.left = 0;
178                 rect.top = 0;
179                 rect.right = window->w;
180                 rect.bottom = window->h;
181                 menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
182                 AdjustWindowRectEx(&rect, style, menu, 0);
183                 w = (rect.right - rect.left);
184                 h = (rect.bottom - rect.top);
185                 x = window->x + rect.left;
186                 y = window->y + rect.top;
187 
188                 SetWindowPos(hwnd, HWND_NOTOPMOST, x, y, w, h, SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE);
189             } else {
190                 window->w = w;
191                 window->h = h;
192             }
193         }
194     }
195     {
196         POINT point;
197         point.x = 0;
198         point.y = 0;
199         if (ClientToScreen(hwnd, &point)) {
200             window->x = point.x;
201             window->y = point.y;
202         }
203     }
204     {
205         DWORD style = GetWindowLong(hwnd, GWL_STYLE);
206         if (style & WS_VISIBLE) {
207             window->flags |= SDL_WINDOW_SHOWN;
208         } else {
209             window->flags &= ~SDL_WINDOW_SHOWN;
210         }
211         if (style & (WS_BORDER | WS_THICKFRAME)) {
212             window->flags &= ~SDL_WINDOW_BORDERLESS;
213         } else {
214             window->flags |= SDL_WINDOW_BORDERLESS;
215         }
216         if (style & WS_THICKFRAME) {
217             window->flags |= SDL_WINDOW_RESIZABLE;
218         } else {
219             window->flags &= ~SDL_WINDOW_RESIZABLE;
220         }
221 #ifdef WS_MAXIMIZE
222         if (style & WS_MAXIMIZE) {
223             window->flags |= SDL_WINDOW_MAXIMIZED;
224         } else
225 #endif
226         {
227             window->flags &= ~SDL_WINDOW_MAXIMIZED;
228         }
229 #ifdef WS_MINIMIZE
230         if (style & WS_MINIMIZE) {
231             window->flags |= SDL_WINDOW_MINIMIZED;
232         } else
233 #endif
234         {
235             window->flags &= ~SDL_WINDOW_MINIMIZED;
236         }
237     }
238     if (GetFocus() == hwnd) {
239         window->flags |= SDL_WINDOW_INPUT_FOCUS;
240         SDL_SetKeyboardFocus(data->window);
241 
242         if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
243             RECT rect;
244             GetClientRect(hwnd, &rect);
245             ClientToScreen(hwnd, (LPPOINT) & rect);
246             ClientToScreen(hwnd, (LPPOINT) & rect + 1);
247             ClipCursor(&rect);
248         }
249     }
250 
251     /* Enable multi-touch */
252     if (videodata->RegisterTouchWindow) {
253         videodata->RegisterTouchWindow(hwnd, (TWF_FINETOUCH|TWF_WANTPALM));
254     }
255 
256     /* Enable dropping files */
257     DragAcceptFiles(hwnd, TRUE);
258 
259     data->initializing = SDL_FALSE;
260 
261     /* All done! */
262     return 0;
263 }
264 
265 int
WIN_CreateWindow(_THIS,SDL_Window * window)266 WIN_CreateWindow(_THIS, SDL_Window * window)
267 {
268     HWND hwnd;
269     RECT rect;
270     DWORD style = STYLE_BASIC;
271     int x, y;
272     int w, h;
273 
274     style |= GetWindowStyle(window);
275 
276     /* Figure out what the window area will be */
277     rect.left = window->x;
278     rect.top = window->y;
279     rect.right = window->x + window->w;
280     rect.bottom = window->y + window->h;
281     AdjustWindowRectEx(&rect, style, FALSE, 0);
282     x = rect.left;
283     y = rect.top;
284     w = (rect.right - rect.left);
285     h = (rect.bottom - rect.top);
286 
287     hwnd =
288         CreateWindow(SDL_Appname, TEXT(""), style, x, y, w, h, NULL, NULL,
289                      SDL_Instance, NULL);
290     if (!hwnd) {
291         return WIN_SetError("Couldn't create window");
292     }
293 
294     WIN_PumpEvents(_this);
295 
296     if (SetupWindowData(_this, window, hwnd, SDL_TRUE) < 0) {
297         DestroyWindow(hwnd);
298         return -1;
299     }
300 
301 #if SDL_VIDEO_OPENGL_WGL
302     /* We need to initialize the extensions before deciding how to create ES profiles */
303     if (window->flags & SDL_WINDOW_OPENGL) {
304         WIN_GL_InitExtensions(_this);
305     }
306 #endif
307 
308 #if SDL_VIDEO_OPENGL_ES2
309     if ((window->flags & SDL_WINDOW_OPENGL) &&
310         _this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES
311 #if SDL_VIDEO_OPENGL_WGL
312         && (!_this->gl_data || !_this->gl_data->HAS_WGL_EXT_create_context_es2_profile)
313 #endif
314         ) {
315 #if SDL_VIDEO_OPENGL_EGL
316         if (WIN_GLES_SetupWindow(_this, window) < 0) {
317             WIN_DestroyWindow(_this, window);
318             return -1;
319         }
320 #else
321         return SDL_SetError("Could not create GLES window surface (no EGL support available)");
322 #endif /* SDL_VIDEO_OPENGL_EGL */
323     } else
324 #endif /* SDL_VIDEO_OPENGL_ES2 */
325 
326 #if SDL_VIDEO_OPENGL_WGL
327     if (window->flags & SDL_WINDOW_OPENGL) {
328         if (WIN_GL_SetupWindow(_this, window) < 0) {
329             WIN_DestroyWindow(_this, window);
330             return -1;
331         }
332     }
333 #endif
334 
335     return 0;
336 }
337 
338 int
WIN_CreateWindowFrom(_THIS,SDL_Window * window,const void * data)339 WIN_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
340 {
341     HWND hwnd = (HWND) data;
342     LPTSTR title;
343     int titleLen;
344 
345     /* Query the title from the existing window */
346     titleLen = GetWindowTextLength(hwnd);
347     title = SDL_stack_alloc(TCHAR, titleLen + 1);
348     if (title) {
349         titleLen = GetWindowText(hwnd, title, titleLen);
350     } else {
351         titleLen = 0;
352     }
353     if (titleLen > 0) {
354         window->title = WIN_StringToUTF8(title);
355     }
356     if (title) {
357         SDL_stack_free(title);
358     }
359 
360     if (SetupWindowData(_this, window, hwnd, SDL_FALSE) < 0) {
361         return -1;
362     }
363 
364 #if SDL_VIDEO_OPENGL_WGL
365     {
366         const char *hint = SDL_GetHint(SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT);
367         if (hint) {
368             /* This hint is a pointer (in string form) of the address of
369                the window to share a pixel format with
370             */
371             SDL_Window *otherWindow = NULL;
372             SDL_sscanf(hint, "%p", (void**)&otherWindow);
373 
374             /* Do some error checking on the pointer */
375             if (otherWindow != NULL && otherWindow->magic == &_this->window_magic)
376             {
377                 /* If the otherWindow has SDL_WINDOW_OPENGL set, set it for the new window as well */
378                 if (otherWindow->flags & SDL_WINDOW_OPENGL)
379                 {
380                     window->flags |= SDL_WINDOW_OPENGL;
381                     if(!WIN_GL_SetPixelFormatFrom(_this, otherWindow, window)) {
382                         return -1;
383                     }
384                 }
385             }
386         }
387     }
388 #endif
389     return 0;
390 }
391 
392 void
WIN_SetWindowTitle(_THIS,SDL_Window * window)393 WIN_SetWindowTitle(_THIS, SDL_Window * window)
394 {
395     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
396     LPTSTR title = WIN_UTF8ToString(window->title);
397     SetWindowText(hwnd, title);
398     SDL_free(title);
399 }
400 
401 void
WIN_SetWindowIcon(_THIS,SDL_Window * window,SDL_Surface * icon)402 WIN_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
403 {
404     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
405     HICON hicon = NULL;
406     BYTE *icon_bmp;
407     int icon_len, y;
408     SDL_RWops *dst;
409 
410     /* Create temporary bitmap buffer */
411     icon_len = 40 + icon->h * icon->w * 4;
412     icon_bmp = SDL_stack_alloc(BYTE, icon_len);
413     dst = SDL_RWFromMem(icon_bmp, icon_len);
414     if (!dst) {
415         SDL_stack_free(icon_bmp);
416         return;
417     }
418 
419     /* Write the BITMAPINFO header */
420     SDL_WriteLE32(dst, 40);
421     SDL_WriteLE32(dst, icon->w);
422     SDL_WriteLE32(dst, icon->h * 2);
423     SDL_WriteLE16(dst, 1);
424     SDL_WriteLE16(dst, 32);
425     SDL_WriteLE32(dst, BI_RGB);
426     SDL_WriteLE32(dst, icon->h * icon->w * 4);
427     SDL_WriteLE32(dst, 0);
428     SDL_WriteLE32(dst, 0);
429     SDL_WriteLE32(dst, 0);
430     SDL_WriteLE32(dst, 0);
431 
432     /* Write the pixels upside down into the bitmap buffer */
433     SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888);
434     y = icon->h;
435     while (y--) {
436         Uint8 *src = (Uint8 *) icon->pixels + y * icon->pitch;
437         SDL_RWwrite(dst, src, icon->pitch, 1);
438     }
439 
440     hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
441 
442     SDL_RWclose(dst);
443     SDL_stack_free(icon_bmp);
444 
445     /* Set the icon for the window */
446     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) hicon);
447 
448     /* Set the icon in the task manager (should we do this?) */
449     SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) hicon);
450 }
451 
452 void
WIN_SetWindowPosition(_THIS,SDL_Window * window)453 WIN_SetWindowPosition(_THIS, SDL_Window * window)
454 {
455     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE);
456 }
457 
458 void
WIN_SetWindowSize(_THIS,SDL_Window * window)459 WIN_SetWindowSize(_THIS, SDL_Window * window)
460 {
461     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOACTIVATE);
462 }
463 
464 void
WIN_ShowWindow(_THIS,SDL_Window * window)465 WIN_ShowWindow(_THIS, SDL_Window * window)
466 {
467     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
468     ShowWindow(hwnd, SW_SHOW);
469 }
470 
471 void
WIN_HideWindow(_THIS,SDL_Window * window)472 WIN_HideWindow(_THIS, SDL_Window * window)
473 {
474     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
475     ShowWindow(hwnd, SW_HIDE);
476 }
477 
478 void
WIN_RaiseWindow(_THIS,SDL_Window * window)479 WIN_RaiseWindow(_THIS, SDL_Window * window)
480 {
481     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
482     SetForegroundWindow(hwnd);
483 }
484 
485 void
WIN_MaximizeWindow(_THIS,SDL_Window * window)486 WIN_MaximizeWindow(_THIS, SDL_Window * window)
487 {
488     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
489     HWND hwnd = data->hwnd;
490     data->expected_resize = SDL_TRUE;
491     ShowWindow(hwnd, SW_MAXIMIZE);
492     data->expected_resize = SDL_FALSE;
493 }
494 
495 void
WIN_MinimizeWindow(_THIS,SDL_Window * window)496 WIN_MinimizeWindow(_THIS, SDL_Window * window)
497 {
498     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
499     ShowWindow(hwnd, SW_MINIMIZE);
500 }
501 
502 void
WIN_SetWindowBordered(_THIS,SDL_Window * window,SDL_bool bordered)503 WIN_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
504 {
505     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
506     HWND hwnd = data->hwnd;
507     DWORD style = GetWindowLong(hwnd, GWL_STYLE);
508 
509     if (bordered) {
510         style &= ~STYLE_BORDERLESS;
511         style |= STYLE_NORMAL;
512     } else {
513         style &= ~STYLE_NORMAL;
514         style |= STYLE_BORDERLESS;
515     }
516 
517     data->in_border_change = SDL_TRUE;
518     SetWindowLong(hwnd, GWL_STYLE, style);
519     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE);
520     data->in_border_change = SDL_FALSE;
521 }
522 
523 void
WIN_SetWindowResizable(_THIS,SDL_Window * window,SDL_bool resizable)524 WIN_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable)
525 {
526     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
527     HWND hwnd = data->hwnd;
528     DWORD style = GetWindowLong(hwnd, GWL_STYLE);
529 
530     if (resizable) {
531         style |= STYLE_RESIZABLE;
532     } else {
533         style &= ~STYLE_RESIZABLE;
534     }
535 
536     SetWindowLong(hwnd, GWL_STYLE, style);
537 }
538 
539 void
WIN_RestoreWindow(_THIS,SDL_Window * window)540 WIN_RestoreWindow(_THIS, SDL_Window * window)
541 {
542     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
543     HWND hwnd = data->hwnd;
544     data->expected_resize = SDL_TRUE;
545     ShowWindow(hwnd, SW_RESTORE);
546     data->expected_resize = SDL_FALSE;
547 }
548 
549 void
WIN_SetWindowFullscreen(_THIS,SDL_Window * window,SDL_VideoDisplay * display,SDL_bool fullscreen)550 WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
551 {
552     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
553     HWND hwnd = data->hwnd;
554     RECT rect;
555     SDL_Rect bounds;
556     DWORD style;
557     HWND top;
558     BOOL menu;
559     int x, y;
560     int w, h;
561 
562     if (SDL_ShouldAllowTopmost() && (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) {
563         top = HWND_TOPMOST;
564     } else {
565         top = HWND_NOTOPMOST;
566     }
567 
568     style = GetWindowLong(hwnd, GWL_STYLE);
569     style &= ~STYLE_MASK;
570     style |= GetWindowStyle(window);
571 
572     WIN_GetDisplayBounds(_this, display, &bounds);
573 
574     if (fullscreen) {
575         x = bounds.x;
576         y = bounds.y;
577         w = bounds.w;
578         h = bounds.h;
579 
580         /* Unset the maximized flag.  This fixes
581            https://bugzilla.libsdl.org/show_bug.cgi?id=3215
582         */
583         if (style & WS_MAXIMIZE) {
584             data->windowed_mode_was_maximized = SDL_TRUE;
585             style &= ~WS_MAXIMIZE;
586         }
587     } else {
588         /* Restore window-maximization state, as applicable.
589            Special care is taken to *not* do this if and when we're
590            alt-tab'ing away (to some other window; as indicated by
591            in_window_deactivation), otherwise
592            https://bugzilla.libsdl.org/show_bug.cgi?id=3215 can reproduce!
593         */
594         if (data->windowed_mode_was_maximized && !data->in_window_deactivation) {
595             style |= WS_MAXIMIZE;
596             data->windowed_mode_was_maximized = SDL_FALSE;
597         }
598         rect.left = 0;
599         rect.top = 0;
600         rect.right = window->windowed.w;
601         rect.bottom = window->windowed.h;
602         menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
603         AdjustWindowRectEx(&rect, style, menu, 0);
604         w = (rect.right - rect.left);
605         h = (rect.bottom - rect.top);
606         x = window->windowed.x + rect.left;
607         y = window->windowed.y + rect.top;
608     }
609     SetWindowLong(hwnd, GWL_STYLE, style);
610     data->expected_resize = SDL_TRUE;
611     SetWindowPos(hwnd, top, x, y, w, h, SWP_NOCOPYBITS | SWP_NOACTIVATE);
612     data->expected_resize = SDL_FALSE;
613 }
614 
615 int
WIN_SetWindowGammaRamp(_THIS,SDL_Window * window,const Uint16 * ramp)616 WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
617 {
618     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
619     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
620     HDC hdc;
621     BOOL succeeded = FALSE;
622 
623     hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
624     if (hdc) {
625         succeeded = SetDeviceGammaRamp(hdc, (LPVOID)ramp);
626         if (!succeeded) {
627             WIN_SetError("SetDeviceGammaRamp()");
628         }
629         DeleteDC(hdc);
630     }
631     return succeeded ? 0 : -1;
632 }
633 
634 int
WIN_GetWindowGammaRamp(_THIS,SDL_Window * window,Uint16 * ramp)635 WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
636 {
637     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
638     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
639     HDC hdc;
640     BOOL succeeded = FALSE;
641 
642     hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
643     if (hdc) {
644         succeeded = GetDeviceGammaRamp(hdc, (LPVOID)ramp);
645         if (!succeeded) {
646             WIN_SetError("GetDeviceGammaRamp()");
647         }
648         DeleteDC(hdc);
649     }
650     return succeeded ? 0 : -1;
651 }
652 
653 void
WIN_SetWindowGrab(_THIS,SDL_Window * window,SDL_bool grabbed)654 WIN_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
655 {
656     WIN_UpdateClipCursor(window);
657 
658     if (window->flags & SDL_WINDOW_FULLSCREEN) {
659         UINT flags = SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE;
660 
661         if (!(window->flags & SDL_WINDOW_SHOWN)) {
662             flags |= SWP_NOACTIVATE;
663         }
664         WIN_SetWindowPositionInternal(_this, window, flags);
665     }
666 }
667 
668 void
WIN_DestroyWindow(_THIS,SDL_Window * window)669 WIN_DestroyWindow(_THIS, SDL_Window * window)
670 {
671     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
672 
673     if (data) {
674         ReleaseDC(data->hwnd, data->hdc);
675         RemoveProp(data->hwnd, TEXT("SDL_WindowData"));
676         if (data->created) {
677             DestroyWindow(data->hwnd);
678         } else {
679             /* Restore any original event handler... */
680             if (data->wndproc != NULL) {
681 #ifdef GWLP_WNDPROC
682                 SetWindowLongPtr(data->hwnd, GWLP_WNDPROC,
683                                  (LONG_PTR) data->wndproc);
684 #else
685                 SetWindowLong(data->hwnd, GWL_WNDPROC,
686                               (LONG_PTR) data->wndproc);
687 #endif
688             }
689         }
690         SDL_free(data);
691     }
692     window->driverdata = NULL;
693 }
694 
695 SDL_bool
WIN_GetWindowWMInfo(_THIS,SDL_Window * window,SDL_SysWMinfo * info)696 WIN_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
697 {
698     const SDL_WindowData *data = (const SDL_WindowData *) window->driverdata;
699     if (info->version.major <= SDL_MAJOR_VERSION) {
700         info->subsystem = SDL_SYSWM_WINDOWS;
701         info->info.win.window = data->hwnd;
702         info->info.win.hdc = data->hdc;
703         return SDL_TRUE;
704     } else {
705         SDL_SetError("Application not compiled with SDL %d.%d\n",
706                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
707         return SDL_FALSE;
708     }
709 }
710 
711 
712 /*
713  * Creates a HelperWindow used for DirectInput events.
714  */
715 int
SDL_HelperWindowCreate(void)716 SDL_HelperWindowCreate(void)
717 {
718     HINSTANCE hInstance = GetModuleHandle(NULL);
719     WNDCLASS wce;
720 
721     /* Make sure window isn't created twice. */
722     if (SDL_HelperWindow != NULL) {
723         return 0;
724     }
725 
726     /* Create the class. */
727     SDL_zero(wce);
728     wce.lpfnWndProc = DefWindowProc;
729     wce.lpszClassName = (LPCWSTR) SDL_HelperWindowClassName;
730     wce.hInstance = hInstance;
731 
732     /* Register the class. */
733     SDL_HelperWindowClass = RegisterClass(&wce);
734     if (SDL_HelperWindowClass == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) {
735         return WIN_SetError("Unable to create Helper Window Class");
736     }
737 
738     /* Create the window. */
739     SDL_HelperWindow = CreateWindowEx(0, SDL_HelperWindowClassName,
740                                       SDL_HelperWindowName,
741                                       WS_OVERLAPPED, CW_USEDEFAULT,
742                                       CW_USEDEFAULT, CW_USEDEFAULT,
743                                       CW_USEDEFAULT, HWND_MESSAGE, NULL,
744                                       hInstance, NULL);
745     if (SDL_HelperWindow == NULL) {
746         UnregisterClass(SDL_HelperWindowClassName, hInstance);
747         return WIN_SetError("Unable to create Helper Window");
748     }
749 
750     return 0;
751 }
752 
753 
754 /*
755  * Destroys the HelperWindow previously created with SDL_HelperWindowCreate.
756  */
757 void
SDL_HelperWindowDestroy(void)758 SDL_HelperWindowDestroy(void)
759 {
760     HINSTANCE hInstance = GetModuleHandle(NULL);
761 
762     /* Destroy the window. */
763     if (SDL_HelperWindow != NULL) {
764         if (DestroyWindow(SDL_HelperWindow) == 0) {
765             WIN_SetError("Unable to destroy Helper Window");
766             return;
767         }
768         SDL_HelperWindow = NULL;
769     }
770 
771     /* Unregister the class. */
772     if (SDL_HelperWindowClass != 0) {
773         if ((UnregisterClass(SDL_HelperWindowClassName, hInstance)) == 0) {
774             WIN_SetError("Unable to destroy Helper Window Class");
775             return;
776         }
777         SDL_HelperWindowClass = 0;
778     }
779 }
780 
WIN_OnWindowEnter(_THIS,SDL_Window * window)781 void WIN_OnWindowEnter(_THIS, SDL_Window * window)
782 {
783 #ifdef WM_MOUSELEAVE
784     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
785     TRACKMOUSEEVENT trackMouseEvent;
786 
787     if (!data || !data->hwnd) {
788         /* The window wasn't fully initialized */
789         return;
790     }
791 
792     trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
793     trackMouseEvent.dwFlags = TME_LEAVE;
794     trackMouseEvent.hwndTrack = data->hwnd;
795 
796     TrackMouseEvent(&trackMouseEvent);
797 #endif /* WM_MOUSELEAVE */
798 }
799 
800 void
WIN_UpdateClipCursor(SDL_Window * window)801 WIN_UpdateClipCursor(SDL_Window *window)
802 {
803     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
804     SDL_Mouse *mouse = SDL_GetMouse();
805 
806     if (data->focus_click_pending) {
807         return;
808     }
809 
810     if ((mouse->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
811         (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
812         if (mouse->relative_mode && !mouse->relative_mode_warp) {
813             LONG cx, cy;
814             RECT rect;
815             GetWindowRect(data->hwnd, &rect);
816 
817             cx = (rect.left + rect.right) / 2;
818             cy = (rect.top + rect.bottom) / 2;
819 
820             /* Make an absurdly small clip rect */
821             rect.left = cx - 1;
822             rect.right = cx + 1;
823             rect.top = cy - 1;
824             rect.bottom = cy + 1;
825 
826             ClipCursor(&rect);
827         } else {
828             RECT rect;
829             if (GetClientRect(data->hwnd, &rect) && !IsRectEmpty(&rect)) {
830                 ClientToScreen(data->hwnd, (LPPOINT) & rect);
831                 ClientToScreen(data->hwnd, (LPPOINT) & rect + 1);
832                 ClipCursor(&rect);
833             }
834         }
835     } else {
836         ClipCursor(NULL);
837     }
838 }
839 
840 int
WIN_SetWindowHitTest(SDL_Window * window,SDL_bool enabled)841 WIN_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
842 {
843     return 0;  /* just succeed, the real work is done elsewhere. */
844 }
845 
846 int
WIN_SetWindowOpacity(_THIS,SDL_Window * window,float opacity)847 WIN_SetWindowOpacity(_THIS, SDL_Window * window, float opacity)
848 {
849     const SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
850     const HWND hwnd = data->hwnd;
851     const LONG style = GetWindowLong(hwnd, GWL_EXSTYLE);
852 
853     SDL_assert(style != 0);
854 
855     if (opacity == 1.0f) {
856         /* want it fully opaque, just mark it unlayered if necessary. */
857         if (style & WS_EX_LAYERED) {
858             if (SetWindowLong(hwnd, GWL_EXSTYLE, style & ~WS_EX_LAYERED) == 0) {
859                 return WIN_SetError("SetWindowLong()");
860             }
861         }
862     } else {
863         const BYTE alpha = (BYTE) ((int) (opacity * 255.0f));
864         /* want it transparent, mark it layered if necessary. */
865         if ((style & WS_EX_LAYERED) == 0) {
866             if (SetWindowLong(hwnd, GWL_EXSTYLE, style | WS_EX_LAYERED) == 0) {
867                 return WIN_SetError("SetWindowLong()");
868             }
869         }
870 
871         if (SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA) == 0) {
872             return WIN_SetError("SetLayeredWindowAttributes()");
873         }
874     }
875 
876     return 0;
877 }
878 
879 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
880 
881 /* vi: set ts=4 sw=4 expandtab: */
882