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