SDL  2.0
SDL_windowswindow.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 /* For borderless Windows, still want the following flags:
55  - WS_CAPTION: this seems to enable the Windows minimize animation
56  - WS_SYSMENU: enables system context menu on task bar
57  - WS_MINIMIZEBOX: window will respond to Windows minimize commands sent to all windows, such as windows key + m, shaking title bar, etc.
58  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
59  */
60 
61 #define STYLE_BASIC (WS_CLIPSIBLINGS | WS_CLIPCHILDREN)
62 #define STYLE_FULLSCREEN (WS_POPUP)
63 #define STYLE_BORDERLESS (WS_POPUP)
64 #define STYLE_BORDERLESS_WINDOWED (WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX)
65 #define STYLE_NORMAL (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX)
66 #define STYLE_RESIZABLE (WS_THICKFRAME | WS_MAXIMIZEBOX)
67 #define STYLE_MASK (STYLE_FULLSCREEN | STYLE_BORDERLESS | STYLE_NORMAL | STYLE_RESIZABLE)
68 
69 static DWORD
70 GetWindowStyle(SDL_Window * window)
71 {
72  DWORD style = 0;
73 
74  if (window->flags & SDL_WINDOW_FULLSCREEN) {
75  style |= STYLE_FULLSCREEN;
76  } else {
77  if (window->flags & SDL_WINDOW_BORDERLESS) {
78  /* SDL 2.1:
79  This behavior more closely matches other platform where the window is borderless
80  but still interacts with the window manager (e.g. task bar shows above it, it can
81  be resized to fit within usable desktop area, etc.) so this should be the behavior
82  for a future SDL release.
83 
84  If you want a borderless window the size of the desktop that looks like a fullscreen
85  window, then you should use the SDL_WINDOW_FULLSCREEN_DESKTOP flag.
86  */
87  if (SDL_GetHintBoolean("SDL_BORDERLESS_WINDOWED_STYLE", SDL_FALSE)) {
88  style |= STYLE_BORDERLESS_WINDOWED;
89  } else {
90  style |= STYLE_BORDERLESS;
91  }
92  } else {
93  style |= STYLE_NORMAL;
94  }
95 
96  /* You can have a borderless resizable window */
97  if (window->flags & SDL_WINDOW_RESIZABLE) {
98  style |= STYLE_RESIZABLE;
99  }
100  }
101  return style;
102 }
103 
104 static void
105 WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x, int *y, int *width, int *height, SDL_bool use_current)
106 {
107  RECT rect;
108 
109  rect.left = 0;
110  rect.top = 0;
111  rect.right = (use_current ? window->w : window->windowed.w);
112  rect.bottom = (use_current ? window->h : window->windowed.h);
113 
114  /* 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
115  expanding the window client area to the previous window + chrome size, so shouldn't need to adjust the window size for the set styles.
116  */
117  if (!(window->flags & SDL_WINDOW_BORDERLESS))
118  AdjustWindowRectEx(&rect, style, menu, 0);
119 
120  *x = (use_current ? window->x : window->windowed.x) + rect.left;
121  *y = (use_current ? window->y : window->windowed.y) + rect.top;
122  *width = (rect.right - rect.left);
123  *height = (rect.bottom - rect.top);
124 }
125 
126 static void
127 WIN_AdjustWindowRect(SDL_Window *window, int *x, int *y, int *width, int *height, SDL_bool use_current)
128 {
130  HWND hwnd = data->hwnd;
131  DWORD style;
132  BOOL menu;
133 
134  style = GetWindowLong(hwnd, GWL_STYLE);
135  menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
136  WIN_AdjustWindowRectWithStyle(window, style, menu, x, y, width, height, use_current);
137 }
138 
139 static void
140 WIN_SetWindowPositionInternal(_THIS, SDL_Window * window, UINT flags)
141 {
142  SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
143  HWND hwnd = data->hwnd;
144  HWND top;
145  int x, y;
146  int w, h;
147 
148  /* Figure out what the window area will be */
150  top = HWND_TOPMOST;
151  } else {
152  top = HWND_NOTOPMOST;
153  }
154 
155  WIN_AdjustWindowRect(window, &x, &y, &w, &h, SDL_TRUE);
156 
157  data->expected_resize = SDL_TRUE;
158  SetWindowPos(hwnd, top, x, y, w, h, flags);
159  data->expected_resize = SDL_FALSE;
160 }
161 
162 static int
163 SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool created)
164 {
165  SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
166  SDL_WindowData *data;
167 
168  /* Allocate the window data */
169  data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
170  if (!data) {
171  return SDL_OutOfMemory();
172  }
173  data->window = window;
174  data->hwnd = hwnd;
175  data->parent = parent;
176  data->hdc = GetDC(hwnd);
177  data->hinstance = (HINSTANCE) GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
178  data->created = created;
179  data->mouse_button_flags = 0;
180  data->videodata = videodata;
181  data->initializing = SDL_TRUE;
182 
183  window->driverdata = data;
184 
185  /* Associate the data with the window */
186  if (!SetProp(hwnd, TEXT("SDL_WindowData"), data)) {
187  ReleaseDC(hwnd, data->hdc);
188  SDL_free(data);
189  return WIN_SetError("SetProp() failed");
190  }
191 
192  /* Set up the window proc function */
193 #ifdef GWLP_WNDPROC
194  data->wndproc = (WNDPROC) GetWindowLongPtr(hwnd, GWLP_WNDPROC);
195  if (data->wndproc == WIN_WindowProc) {
196  data->wndproc = NULL;
197  } else {
198  SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) WIN_WindowProc);
199  }
200 #else
201  data->wndproc = (WNDPROC) GetWindowLong(hwnd, GWL_WNDPROC);
202  if (data->wndproc == WIN_WindowProc) {
203  data->wndproc = NULL;
204  } else {
205  SetWindowLong(hwnd, GWL_WNDPROC, (LONG_PTR) WIN_WindowProc);
206  }
207 #endif
208 
209  /* Fill in the SDL window with the window data */
210  {
211  RECT rect;
212  if (GetClientRect(hwnd, &rect)) {
213  int w = rect.right;
214  int h = rect.bottom;
215  if ((window->windowed.w && window->windowed.w != w) || (window->windowed.h && window->windowed.h != h)) {
216  /* We tried to create a window larger than the desktop and Windows didn't allow it. Override! */
217  int x, y;
218  int w, h;
219 
220  /* Figure out what the window area will be */
221  WIN_AdjustWindowRect(window, &x, &y, &w, &h, SDL_FALSE);
222  SetWindowPos(hwnd, HWND_NOTOPMOST, x, y, w, h, SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE);
223  } else {
224  window->w = w;
225  window->h = h;
226  }
227  }
228  }
229  {
230  POINT point;
231  point.x = 0;
232  point.y = 0;
233  if (ClientToScreen(hwnd, &point)) {
234  window->x = point.x;
235  window->y = point.y;
236  }
237  }
238  {
239  DWORD style = GetWindowLong(hwnd, GWL_STYLE);
240  if (style & WS_VISIBLE) {
241  window->flags |= SDL_WINDOW_SHOWN;
242  } else {
243  window->flags &= ~SDL_WINDOW_SHOWN;
244  }
245  if (style & WS_POPUP) {
246  window->flags |= SDL_WINDOW_BORDERLESS;
247  } else {
248  window->flags &= ~SDL_WINDOW_BORDERLESS;
249  }
250  if (style & WS_THICKFRAME) {
251  window->flags |= SDL_WINDOW_RESIZABLE;
252  } else {
253  window->flags &= ~SDL_WINDOW_RESIZABLE;
254  }
255 #ifdef WS_MAXIMIZE
256  if (style & WS_MAXIMIZE) {
257  window->flags |= SDL_WINDOW_MAXIMIZED;
258  } else
259 #endif
260  {
261  window->flags &= ~SDL_WINDOW_MAXIMIZED;
262  }
263 #ifdef WS_MINIMIZE
264  if (style & WS_MINIMIZE) {
265  window->flags |= SDL_WINDOW_MINIMIZED;
266  } else
267 #endif
268  {
269  window->flags &= ~SDL_WINDOW_MINIMIZED;
270  }
271  }
272  if (GetFocus() == hwnd) {
273  window->flags |= SDL_WINDOW_INPUT_FOCUS;
275 
276  if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
277  RECT rect;
278  GetClientRect(hwnd, &rect);
279  ClientToScreen(hwnd, (LPPOINT) & rect);
280  ClientToScreen(hwnd, (LPPOINT) & rect + 1);
281  ClipCursor(&rect);
282  }
283  }
284 
285  /* Enable multi-touch */
286  if (videodata->RegisterTouchWindow) {
287  videodata->RegisterTouchWindow(hwnd, (TWF_FINETOUCH|TWF_WANTPALM));
288  }
289 
290  /* Enable dropping files */
291  DragAcceptFiles(hwnd, TRUE);
292 
293  data->initializing = SDL_FALSE;
294 
295  /* All done! */
296  return 0;
297 }
298 
299 
300 
301 int
303 {
304  HWND hwnd, parent = NULL;
305  DWORD style = STYLE_BASIC;
306  int x, y;
307  int w, h;
308 
309  if (window->flags & SDL_WINDOW_SKIP_TASKBAR) {
310  parent = CreateWindow(SDL_Appname, TEXT(""), STYLE_BASIC, 0, 0, 32, 32, NULL, NULL, SDL_Instance, NULL);
311  }
312 
313  style |= GetWindowStyle(window);
314 
315  /* Figure out what the window area will be */
316  WIN_AdjustWindowRectWithStyle(window, style, FALSE, &x, &y, &w, &h, SDL_FALSE);
317 
318  hwnd =
319  CreateWindow(SDL_Appname, TEXT(""), style, x, y, w, h, parent, NULL,
320  SDL_Instance, NULL);
321  if (!hwnd) {
322  return WIN_SetError("Couldn't create window");
323  }
324 
326 
327  if (SetupWindowData(_this, window, hwnd, parent, SDL_TRUE) < 0) {
328  DestroyWindow(hwnd);
329  if (parent) {
330  DestroyWindow(parent);
331  }
332  return -1;
333  }
334 
335  /* Inform Windows of the frame change so we can respond to WM_NCCALCSIZE */
336  SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
337 
338  if (!(window->flags & SDL_WINDOW_OPENGL)) {
339  return 0;
340  }
341 
342  /* The rest of this macro mess is for OpenGL or OpenGL ES windows */
343 #if SDL_VIDEO_OPENGL_ES2
346  && (!_this->gl_data || WIN_GL_UseEGL(_this))
347 #endif /* SDL_VIDEO_OPENGL_WGL */
348  ) {
349 #if SDL_VIDEO_OPENGL_EGL
350  if (WIN_GLES_SetupWindow(_this, window) < 0) {
351  WIN_DestroyWindow(_this, window);
352  return -1;
353  }
354  return 0;
355 #else
356  return SDL_SetError("Could not create GLES window surface (EGL support not configured)");
357 #endif /* SDL_VIDEO_OPENGL_EGL */
358  }
359 #endif /* SDL_VIDEO_OPENGL_ES2 */
360 
361 #if SDL_VIDEO_OPENGL_WGL
362  if (WIN_GL_SetupWindow(_this, window) < 0) {
363  WIN_DestroyWindow(_this, window);
364  return -1;
365  }
366 #else
367  return SDL_SetError("Could not create GL window (WGL support not configured)");
368 #endif
369 
370  return 0;
371 }
372 
373 int
374 WIN_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
375 {
376  HWND hwnd = (HWND) data;
377  LPTSTR title;
378  int titleLen;
379 
380  /* Query the title from the existing window */
381  titleLen = GetWindowTextLength(hwnd);
382  title = SDL_stack_alloc(TCHAR, titleLen + 1);
383  if (title) {
384  titleLen = GetWindowText(hwnd, title, titleLen);
385  } else {
386  titleLen = 0;
387  }
388  if (titleLen > 0) {
389  window->title = WIN_StringToUTF8(title);
390  }
391  if (title) {
392  SDL_stack_free(title);
393  }
394 
395  if (SetupWindowData(_this, window, hwnd, GetParent(hwnd), SDL_FALSE) < 0) {
396  return -1;
397  }
398 
399 #if SDL_VIDEO_OPENGL_WGL
400  {
402  if (hint) {
403  /* This hint is a pointer (in string form) of the address of
404  the window to share a pixel format with
405  */
406  SDL_Window *otherWindow = NULL;
407  SDL_sscanf(hint, "%p", (void**)&otherWindow);
408 
409  /* Do some error checking on the pointer */
410  if (otherWindow != NULL && otherWindow->magic == &_this->window_magic)
411  {
412  /* If the otherWindow has SDL_WINDOW_OPENGL set, set it for the new window as well */
413  if (otherWindow->flags & SDL_WINDOW_OPENGL)
414  {
415  window->flags |= SDL_WINDOW_OPENGL;
416  if(!WIN_GL_SetPixelFormatFrom(_this, otherWindow, window)) {
417  return -1;
418  }
419  }
420  }
421  }
422  }
423 #endif
424  return 0;
425 }
426 
427 void
429 {
430  HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
431  LPTSTR title = WIN_UTF8ToString(window->title);
432  SetWindowText(hwnd, title);
433  SDL_free(title);
434 }
435 
436 void
438 {
439  HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
440  HICON hicon = NULL;
441  BYTE *icon_bmp;
442  int icon_len, mask_len, y;
443  SDL_RWops *dst;
444 
445  /* Create temporary buffer for ICONIMAGE structure */
446  mask_len = (icon->h * (icon->w + 7)/8);
447  icon_len = 40 + icon->h * icon->w * sizeof(Uint32) + mask_len;
448  icon_bmp = SDL_stack_alloc(BYTE, icon_len);
449  dst = SDL_RWFromMem(icon_bmp, icon_len);
450  if (!dst) {
451  SDL_stack_free(icon_bmp);
452  return;
453  }
454 
455  /* Write the BITMAPINFO header */
456  SDL_WriteLE32(dst, 40);
457  SDL_WriteLE32(dst, icon->w);
458  SDL_WriteLE32(dst, icon->h * 2);
459  SDL_WriteLE16(dst, 1);
460  SDL_WriteLE16(dst, 32);
461  SDL_WriteLE32(dst, BI_RGB);
462  SDL_WriteLE32(dst, icon->h * icon->w * sizeof(Uint32));
463  SDL_WriteLE32(dst, 0);
464  SDL_WriteLE32(dst, 0);
465  SDL_WriteLE32(dst, 0);
466  SDL_WriteLE32(dst, 0);
467 
468  /* Write the pixels upside down into the bitmap buffer */
470  y = icon->h;
471  while (y--) {
472  Uint8 *src = (Uint8 *) icon->pixels + y * icon->pitch;
473  SDL_RWwrite(dst, src, icon->w * sizeof(Uint32), 1);
474  }
475 
476  /* Write the mask */
477  SDL_memset(icon_bmp + icon_len - mask_len, 0xFF, mask_len);
478 
479  hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
480 
481  SDL_RWclose(dst);
482  SDL_stack_free(icon_bmp);
483 
484  /* Set the icon for the window */
485  SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) hicon);
486 
487  /* Set the icon in the task manager (should we do this?) */
488  SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) hicon);
489 }
490 
491 void
493 {
494  WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE);
495 }
496 
497 void
499 {
500  WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOACTIVATE);
501 }
502 
503 int
504 WIN_GetWindowBordersSize(_THIS, SDL_Window * window, int *top, int *left, int *bottom, int *right)
505 {
506  HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
507  RECT rcClient, rcWindow;
508  POINT ptDiff;
509 
510  /* rcClient stores the size of the inner window, while rcWindow stores the outer size relative to the top-left
511  * screen position; so the top/left values of rcClient are always {0,0} and bottom/right are {height,width} */
512  GetClientRect(hwnd, &rcClient);
513  GetWindowRect(hwnd, &rcWindow);
514 
515  /* convert the top/left values to make them relative to
516  * the window; they will end up being slightly negative */
517  ptDiff.y = rcWindow.top;
518  ptDiff.x = rcWindow.left;
519 
520  ScreenToClient(hwnd, &ptDiff);
521 
522  rcWindow.top = ptDiff.y;
523  rcWindow.left = ptDiff.x;
524 
525  /* convert the bottom/right values to make them relative to the window,
526  * these will be slightly bigger than the inner width/height */
527  ptDiff.y = rcWindow.bottom;
528  ptDiff.x = rcWindow.right;
529 
530  ScreenToClient(hwnd, &ptDiff);
531 
532  rcWindow.bottom = ptDiff.y;
533  rcWindow.right = ptDiff.x;
534 
535  /* Now that both the inner and outer rects use the same coordinate system we can substract them to get the border size.
536  * Keep in mind that the top/left coordinates of rcWindow are negative because the border lies slightly before {0,0},
537  * so switch them around because SDL2 wants them in positive. */
538  *top = rcClient.top - rcWindow.top;
539  *left = rcClient.left - rcWindow.left;
540  *bottom = rcWindow.bottom - rcClient.bottom;
541  *right = rcWindow.right - rcClient.right;
542 
543  return 0;
544 }
545 
546 void
548 {
549  HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
550  ShowWindow(hwnd, SW_SHOW);
551 }
552 
553 void
555 {
556  HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
557  ShowWindow(hwnd, SW_HIDE);
558 }
559 
560 void
562 {
563  HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
564  SetForegroundWindow(hwnd);
565 }
566 
567 void
569 {
570  SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
571  HWND hwnd = data->hwnd;
572  data->expected_resize = SDL_TRUE;
573  ShowWindow(hwnd, SW_MAXIMIZE);
574  data->expected_resize = SDL_FALSE;
575 }
576 
577 void
579 {
580  HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
581  ShowWindow(hwnd, SW_MINIMIZE);
582 }
583 
584 void
585 WIN_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
586 {
587  SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
588  HWND hwnd = data->hwnd;
589  DWORD style;
590 
591  style = GetWindowLong(hwnd, GWL_STYLE);
592  style &= ~STYLE_MASK;
593  style |= GetWindowStyle(window);
594 
595  data->in_border_change = SDL_TRUE;
596  SetWindowLong(hwnd, GWL_STYLE, style);
597  WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE);
598  data->in_border_change = SDL_FALSE;
599 }
600 
601 void
602 WIN_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable)
603 {
604  SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
605  HWND hwnd = data->hwnd;
606  DWORD style;
607 
608  style = GetWindowLong(hwnd, GWL_STYLE);
609  style &= ~STYLE_MASK;
610  style |= GetWindowStyle(window);
611 
612  SetWindowLong(hwnd, GWL_STYLE, style);
613 }
614 
615 void
617 {
618  SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
619  HWND hwnd = data->hwnd;
620  data->expected_resize = SDL_TRUE;
621  ShowWindow(hwnd, SW_RESTORE);
622  data->expected_resize = SDL_FALSE;
623 }
624 
625 void
626 WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
627 {
628  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
629  HWND hwnd = data->hwnd;
630  SDL_Rect bounds;
631  DWORD style;
632  HWND top;
633  int x, y;
634  int w, h;
635 
637  top = HWND_TOPMOST;
638  } else {
639  top = HWND_NOTOPMOST;
640  }
641 
642  style = GetWindowLong(hwnd, GWL_STYLE);
643  style &= ~STYLE_MASK;
644  style |= GetWindowStyle(window);
645 
646  WIN_GetDisplayBounds(_this, display, &bounds);
647 
648  if (fullscreen) {
649  x = bounds.x;
650  y = bounds.y;
651  w = bounds.w;
652  h = bounds.h;
653 
654  /* Unset the maximized flag. This fixes
655  https://bugzilla.libsdl.org/show_bug.cgi?id=3215
656  */
657  if (style & WS_MAXIMIZE) {
659  style &= ~WS_MAXIMIZE;
660  }
661  } else {
662  BOOL menu;
663 
664  /* Restore window-maximization state, as applicable.
665  Special care is taken to *not* do this if and when we're
666  alt-tab'ing away (to some other window; as indicated by
667  in_window_deactivation), otherwise
668  https://bugzilla.libsdl.org/show_bug.cgi?id=3215 can reproduce!
669  */
671  style |= WS_MAXIMIZE;
673  }
674 
675  menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
676  WIN_AdjustWindowRectWithStyle(window, style, menu, &x, &y, &w, &h, SDL_FALSE);
677  }
678  SetWindowLong(hwnd, GWL_STYLE, style);
679  data->expected_resize = SDL_TRUE;
680  SetWindowPos(hwnd, top, x, y, w, h, SWP_NOCOPYBITS | SWP_NOACTIVATE);
681  data->expected_resize = SDL_FALSE;
682 }
683 
684 int
685 WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
686 {
687  SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
688  SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
689  HDC hdc;
690  BOOL succeeded = FALSE;
691 
692  hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
693  if (hdc) {
694  succeeded = SetDeviceGammaRamp(hdc, (LPVOID)ramp);
695  if (!succeeded) {
696  WIN_SetError("SetDeviceGammaRamp()");
697  }
698  DeleteDC(hdc);
699  }
700  return succeeded ? 0 : -1;
701 }
702 
703 int
705 {
706  SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
707  SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
708  HDC hdc;
709  BOOL succeeded = FALSE;
710 
711  hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
712  if (hdc) {
713  succeeded = GetDeviceGammaRamp(hdc, (LPVOID)ramp);
714  if (!succeeded) {
715  WIN_SetError("GetDeviceGammaRamp()");
716  }
717  DeleteDC(hdc);
718  }
719  return succeeded ? 0 : -1;
720 }
721 
722 void
723 WIN_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
724 {
725  WIN_UpdateClipCursor(window);
726 
727  if (window->flags & SDL_WINDOW_FULLSCREEN) {
728  UINT flags = SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE;
729 
730  if (!(window->flags & SDL_WINDOW_SHOWN)) {
731  flags |= SWP_NOACTIVATE;
732  }
733  WIN_SetWindowPositionInternal(_this, window, flags);
734  }
735 }
736 
737 void
739 {
740  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
741 
742  if (data) {
743  ReleaseDC(data->hwnd, data->hdc);
744  RemoveProp(data->hwnd, TEXT("SDL_WindowData"));
745  if (data->created) {
746  DestroyWindow(data->hwnd);
747  if (data->parent) {
748  DestroyWindow(data->parent);
749  }
750  } else {
751  /* Restore any original event handler... */
752  if (data->wndproc != NULL) {
753 #ifdef GWLP_WNDPROC
754  SetWindowLongPtr(data->hwnd, GWLP_WNDPROC,
755  (LONG_PTR) data->wndproc);
756 #else
757  SetWindowLong(data->hwnd, GWL_WNDPROC,
758  (LONG_PTR) data->wndproc);
759 #endif
760  }
761  }
762  SDL_free(data);
763  }
764  window->driverdata = NULL;
765 }
766 
767 SDL_bool
769 {
770  const SDL_WindowData *data = (const SDL_WindowData *) window->driverdata;
771  if (info->version.major <= SDL_MAJOR_VERSION) {
772  int versionnum = SDL_VERSIONNUM(info->version.major, info->version.minor, info->version.patch);
773 
775  info->info.win.window = data->hwnd;
776 
777  if (versionnum >= SDL_VERSIONNUM(2, 0, 4)) {
778  info->info.win.hdc = data->hdc;
779  }
780 
781  if (versionnum >= SDL_VERSIONNUM(2, 0, 5)) {
782  info->info.win.hinstance = data->hinstance;
783  }
784 
785  return SDL_TRUE;
786  } else {
787  SDL_SetError("Application not compiled with SDL %d.%d",
789  return SDL_FALSE;
790  }
791 }
792 
793 
794 /*
795  * Creates a HelperWindow used for DirectInput events.
796  */
797 int
798 SDL_HelperWindowCreate(void)
799 {
800  HINSTANCE hInstance = GetModuleHandle(NULL);
801  WNDCLASS wce;
802 
803  /* Make sure window isn't created twice. */
804  if (SDL_HelperWindow != NULL) {
805  return 0;
806  }
807 
808  /* Create the class. */
809  SDL_zero(wce);
810  wce.lpfnWndProc = DefWindowProc;
811  wce.lpszClassName = (LPCWSTR) SDL_HelperWindowClassName;
812  wce.hInstance = hInstance;
813 
814  /* Register the class. */
815  SDL_HelperWindowClass = RegisterClass(&wce);
816  if (SDL_HelperWindowClass == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) {
817  return WIN_SetError("Unable to create Helper Window Class");
818  }
819 
820  /* Create the window. */
821  SDL_HelperWindow = CreateWindowEx(0, SDL_HelperWindowClassName,
822  SDL_HelperWindowName,
823  WS_OVERLAPPED, CW_USEDEFAULT,
824  CW_USEDEFAULT, CW_USEDEFAULT,
825  CW_USEDEFAULT, HWND_MESSAGE, NULL,
826  hInstance, NULL);
827  if (SDL_HelperWindow == NULL) {
828  UnregisterClass(SDL_HelperWindowClassName, hInstance);
829  return WIN_SetError("Unable to create Helper Window");
830  }
831 
832  return 0;
833 }
834 
835 
836 /*
837  * Destroys the HelperWindow previously created with SDL_HelperWindowCreate.
838  */
839 void
840 SDL_HelperWindowDestroy(void)
841 {
842  HINSTANCE hInstance = GetModuleHandle(NULL);
843 
844  /* Destroy the window. */
845  if (SDL_HelperWindow != NULL) {
846  if (DestroyWindow(SDL_HelperWindow) == 0) {
847  WIN_SetError("Unable to destroy Helper Window");
848  return;
849  }
850  SDL_HelperWindow = NULL;
851  }
852 
853  /* Unregister the class. */
854  if (SDL_HelperWindowClass != 0) {
855  if ((UnregisterClass(SDL_HelperWindowClassName, hInstance)) == 0) {
856  WIN_SetError("Unable to destroy Helper Window Class");
857  return;
858  }
859  SDL_HelperWindowClass = 0;
860  }
861 }
862 
863 void WIN_OnWindowEnter(_THIS, SDL_Window * window)
864 {
865  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
866 
867  if (!data || !data->hwnd) {
868  /* The window wasn't fully initialized */
869  return;
870  }
871 
872  if (window->flags & SDL_WINDOW_ALWAYS_ON_TOP) {
873  WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE);
874  }
875 
876 #ifdef WM_MOUSELEAVE
877  {
878  TRACKMOUSEEVENT trackMouseEvent;
879 
880  trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
881  trackMouseEvent.dwFlags = TME_LEAVE;
882  trackMouseEvent.hwndTrack = data->hwnd;
883 
884  TrackMouseEvent(&trackMouseEvent);
885  }
886 #endif /* WM_MOUSELEAVE */
887 }
888 
889 void
891 {
892  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
893  SDL_Mouse *mouse = SDL_GetMouse();
894 
895  if (data->focus_click_pending) {
896  return;
897  }
898 
899  if ((mouse->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
900  (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
901  if (mouse->relative_mode && !mouse->relative_mode_warp) {
902  LONG cx, cy;
903  RECT rect;
904  GetWindowRect(data->hwnd, &rect);
905 
906  cx = (rect.left + rect.right) / 2;
907  cy = (rect.top + rect.bottom) / 2;
908 
909  /* Make an absurdly small clip rect */
910  rect.left = cx - 1;
911  rect.right = cx + 1;
912  rect.top = cy - 1;
913  rect.bottom = cy + 1;
914 
915  ClipCursor(&rect);
916  } else {
917  RECT rect;
918  if (GetClientRect(data->hwnd, &rect) && !IsRectEmpty(&rect)) {
919  ClientToScreen(data->hwnd, (LPPOINT) & rect);
920  ClientToScreen(data->hwnd, (LPPOINT) & rect + 1);
921  ClipCursor(&rect);
922  }
923  }
924  } else {
925  ClipCursor(NULL);
926  }
927 }
928 
929 int
931 {
932  return 0; /* just succeed, the real work is done elsewhere. */
933 }
934 
935 int
936 WIN_SetWindowOpacity(_THIS, SDL_Window * window, float opacity)
937 {
938  const SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
939  const HWND hwnd = data->hwnd;
940  const LONG style = GetWindowLong(hwnd, GWL_EXSTYLE);
941 
942  SDL_assert(style != 0);
943 
944  if (opacity == 1.0f) {
945  /* want it fully opaque, just mark it unlayered if necessary. */
946  if (style & WS_EX_LAYERED) {
947  if (SetWindowLong(hwnd, GWL_EXSTYLE, style & ~WS_EX_LAYERED) == 0) {
948  return WIN_SetError("SetWindowLong()");
949  }
950  }
951  } else {
952  const BYTE alpha = (BYTE) ((int) (opacity * 255.0f));
953  /* want it transparent, mark it layered if necessary. */
954  if ((style & WS_EX_LAYERED) == 0) {
955  if (SetWindowLong(hwnd, GWL_EXSTYLE, style | WS_EX_LAYERED) == 0) {
956  return WIN_SetError("SetWindowLong()");
957  }
958  }
959 
960  if (SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA) == 0) {
961  return WIN_SetError("SetLayeredWindowAttributes()");
962  }
963  }
964 
965  return 0;
966 }
967 
968 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
969 
970 /* vi: set ts=4 sw=4 expandtab: */
#define BI_RGB
Definition: SDL_bmp.c:45
#define SDL_MINOR_VERSION
Definition: SDL_version.h:61
HINSTANCE SDL_Instance
#define WIN_UTF8ToString(S)
Definition: SDL_windows.h:47
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:112
void WIN_SetWindowSize(_THIS, SDL_Window *window)
void SDL_SetKeyboardFocus(SDL_Window *window)
Definition: SDL_keyboard.c:630
GLdouble GLdouble right
GLenum GLenum dst
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
#define SDL_RWwrite(ctx, ptr, size, n)
Definition: SDL_rwops.h:188
#define SDL_MAJOR_VERSION
Definition: SDL_version.h:60
void WIN_RaiseWindow(_THIS, SDL_Window *window)
const void * magic
Definition: SDL_sysvideo.h:75
SDL_Rect rect
Definition: testrelative.c:27
int WIN_GetWindowGammaRamp(_THIS, SDL_Window *window, Uint16 *ramp)
LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
void WIN_DestroyWindow(_THIS, SDL_Window *window)
GLfloat GLfloat GLfloat GLfloat h
SDL_bool WIN_GetWindowWMInfo(_THIS, SDL_Window *window, struct SDL_SysWMinfo *info)
A collection of pixels used in software blitting.
Definition: SDL_surface.h:69
void WIN_MaximizeWindow(_THIS, SDL_Window *window)
#define SDL_GetHint
SDL_version version
Definition: SDL_syswm.h:196
SDL_bool expected_resize
Uint8 major
Definition: SDL_version.h:53
#define SDL_WriteLE16
LPTSTR SDL_Appname
GLint GLint bottom
GLfloat f
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
SDL_SYSWM_TYPE subsystem
Definition: SDL_syswm.h:197
SDL_Window * window
uint32_t Uint32
Definition: SDL_stdinc.h:181
GLenum src
GLdouble GLdouble GLdouble GLdouble top
SDL_Rect windowed
Definition: SDL_sysvideo.h:87
void WIN_OnWindowEnter(_THIS, SDL_Window *window)
GLfloat GLfloat GLfloat alpha
GLint GLint GLsizei width
Definition: SDL_opengl.h:1572
struct SDL_GLDriverData * gl_data
Definition: SDL_sysvideo.h:378
void WIN_SetWindowPosition(_THIS, SDL_Window *window)
int WIN_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
#define SDL_GetHintBoolean
int WIN_CreateWindow(_THIS, SDL_Window *window)
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
SDL_bool windowed_mode_was_maximized
TCHAR DeviceName[32]
SDL_bool in_border_change
int WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)
void WIN_SetWindowResizable(_THIS, SDL_Window *window, SDL_bool resizable)
void * pixels
Definition: SDL_surface.h:75
void WIN_MinimizeWindow(_THIS, SDL_Window *window)
#define _THIS
struct SDL_VideoData * videodata
uint8_t Uint8
Definition: SDL_stdinc.h:157
#define SDL_free
#define SDL_stack_alloc(type, count)
Definition: SDL_stdinc.h:354
#define SDL_VERSIONNUM(X, Y, Z)
Definition: SDL_version.h:94
int WIN_SetWindowOpacity(_THIS, SDL_Window *window, float opacity)
#define TRUE
Definition: edid-parse.c:33
void WIN_SetWindowIcon(_THIS, SDL_Window *window, SDL_Surface *icon)
void WIN_ShowWindow(_THIS, SDL_Window *window)
GLubyte GLubyte GLubyte GLubyte w
#define SDL_RWFromMem
void WIN_UpdateClipCursor(SDL_Window *window)
Uint8 minor
Definition: SDL_version.h:54
#define WIN_StringToUTF8(S)
Definition: SDL_windows.h:46
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
#define SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT
A variable that is the address of another SDL_Window* (as a hex string formatted with "%p")...
Definition: SDL_hints.h:579
#define SDL_sscanf
char * title
Definition: SDL_sysvideo.h:77
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
int x
Definition: SDL_rect.h:66
#define SDL_VIDEO_OPENGL_WGL
#define TWF_FINETOUCH
#define TWF_WANTPALM
int w
Definition: SDL_rect.h:67
void WIN_RestoreWindow(_THIS, SDL_Window *window)
GLenum GLenum GLsizei const GLuint GLboolean enabled
#define SDL_assert(condition)
Definition: SDL_assert.h:169
int WIN_SetWindowGammaRamp(_THIS, SDL_Window *window, const Uint16 *ramp)
Window window
Definition: SDL_syswm.h:218
SDL_bool SDL_ShouldAllowTopmost(void)
Definition: SDL_video.c:3888
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:139
SDL_PixelFormat * format
Definition: SDL_surface.h:72
#define SDL_RWclose(ctx)
Definition: SDL_rwops.h:189
int WIN_SetError(const char *prefix)
#define SDL_SetError
void WIN_SetWindowTitle(_THIS, SDL_Window *window)
GLbitfield flags
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1572
void WIN_PumpEvents(_THIS)
#define SDL_calloc
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
Definition: SDL_video.c:1073
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
void WIN_SetWindowGrab(_THIS, SDL_Window *window, SDL_bool grabbed)
int h
Definition: SDL_rect.h:67
The type used to identify a window.
Definition: SDL_sysvideo.h:73
void WIN_SetWindowFullscreen(_THIS, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen)
#define SDL_WriteLE32
uint16_t Uint16
Definition: SDL_stdinc.h:169
SDL_bool in_window_deactivation
union SDL_SysWMinfo::@18 info
void WIN_SetWindowBordered(_THIS, SDL_Window *window, SDL_bool bordered)
struct SDL_VideoDevice::@34 gl_config
void * driverdata
Definition: SDL_sysvideo.h:111
int WIN_GetWindowBordersSize(_THIS, SDL_Window *window, int *top, int *left, int *bottom, int *right)
int WIN_CreateWindowFrom(_THIS, SDL_Window *window, const void *data)
#define SDL_stack_free(data)
Definition: SDL_stdinc.h:355
void WIN_HideWindow(_THIS, SDL_Window *window)
#define FALSE
Definition: edid-parse.c:34
Uint32 flags
Definition: SDL_sysvideo.h:83
int y
Definition: SDL_rect.h:66
#define SDL_memset
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64
GLint left
Uint8 patch
Definition: SDL_version.h:55