SDL  2.0
SDL_windowswindow.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2019 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  /* Need to set initialize minimize style, or when we call ShowWindow with WS_MINIMIZE it will activate a random window */
102  if (window->flags & SDL_WINDOW_MINIMIZED) {
103  style |= WS_MINIMIZE;
104  }
105  }
106  return style;
107 }
108 
109 static void
110 WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x, int *y, int *width, int *height, SDL_bool use_current)
111 {
112  RECT rect;
113 
114  rect.left = 0;
115  rect.top = 0;
116  rect.right = (use_current ? window->w : window->windowed.w);
117  rect.bottom = (use_current ? window->h : window->windowed.h);
118 
119  /* 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
120  expanding the window client area to the previous window + chrome size, so shouldn't need to adjust the window size for the set styles.
121  */
122  if (!(window->flags & SDL_WINDOW_BORDERLESS))
123  AdjustWindowRectEx(&rect, style, menu, 0);
124 
125  *x = (use_current ? window->x : window->windowed.x) + rect.left;
126  *y = (use_current ? window->y : window->windowed.y) + rect.top;
127  *width = (rect.right - rect.left);
128  *height = (rect.bottom - rect.top);
129 }
130 
131 static void
132 WIN_AdjustWindowRect(SDL_Window *window, int *x, int *y, int *width, int *height, SDL_bool use_current)
133 {
135  HWND hwnd = data->hwnd;
136  DWORD style;
137  BOOL menu;
138 
139  style = GetWindowLong(hwnd, GWL_STYLE);
140  menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
141  WIN_AdjustWindowRectWithStyle(window, style, menu, x, y, width, height, use_current);
142 }
143 
144 static void
145 WIN_SetWindowPositionInternal(_THIS, SDL_Window * window, UINT flags)
146 {
147  SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
148  HWND hwnd = data->hwnd;
149  HWND top;
150  int x, y;
151  int w, h;
152 
153  /* Figure out what the window area will be */
155  top = HWND_TOPMOST;
156  } else {
157  top = HWND_NOTOPMOST;
158  }
159 
160  WIN_AdjustWindowRect(window, &x, &y, &w, &h, SDL_TRUE);
161 
162  data->expected_resize = SDL_TRUE;
163  SetWindowPos(hwnd, top, x, y, w, h, flags);
164  data->expected_resize = SDL_FALSE;
165 }
166 
167 static int
168 SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool created)
169 {
170  SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
171  SDL_WindowData *data;
172 
173  /* Allocate the window data */
174  data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
175  if (!data) {
176  return SDL_OutOfMemory();
177  }
178  data->window = window;
179  data->hwnd = hwnd;
180  data->parent = parent;
181  data->hdc = GetDC(hwnd);
182  data->hinstance = (HINSTANCE) GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
183  data->created = created;
184  data->mouse_button_flags = 0;
185  data->videodata = videodata;
186  data->initializing = SDL_TRUE;
187 
188  window->driverdata = data;
189 
190  /* Associate the data with the window */
191  if (!SetProp(hwnd, TEXT("SDL_WindowData"), data)) {
192  ReleaseDC(hwnd, data->hdc);
193  SDL_free(data);
194  return WIN_SetError("SetProp() failed");
195  }
196 
197  /* Set up the window proc function */
198 #ifdef GWLP_WNDPROC
199  data->wndproc = (WNDPROC) GetWindowLongPtr(hwnd, GWLP_WNDPROC);
200  if (data->wndproc == WIN_WindowProc) {
201  data->wndproc = NULL;
202  } else {
203  SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) WIN_WindowProc);
204  }
205 #else
206  data->wndproc = (WNDPROC) GetWindowLong(hwnd, GWL_WNDPROC);
207  if (data->wndproc == WIN_WindowProc) {
208  data->wndproc = NULL;
209  } else {
210  SetWindowLong(hwnd, GWL_WNDPROC, (LONG_PTR) WIN_WindowProc);
211  }
212 #endif
213 
214  /* Fill in the SDL window with the window data */
215  {
216  RECT rect;
217  if (GetClientRect(hwnd, &rect)) {
218  int w = rect.right;
219  int h = rect.bottom;
220  if ((window->windowed.w && window->windowed.w != w) || (window->windowed.h && window->windowed.h != h)) {
221  /* We tried to create a window larger than the desktop and Windows didn't allow it. Override! */
222  int x, y;
223  /* Figure out what the window area will be */
224  WIN_AdjustWindowRect(window, &x, &y, &w, &h, SDL_FALSE);
225  SetWindowPos(hwnd, HWND_NOTOPMOST, x, y, w, h, SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE);
226  } else {
227  window->w = w;
228  window->h = h;
229  }
230  }
231  }
232  {
233  POINT point;
234  point.x = 0;
235  point.y = 0;
236  if (ClientToScreen(hwnd, &point)) {
237  window->x = point.x;
238  window->y = point.y;
239  }
240  }
241  {
242  DWORD style = GetWindowLong(hwnd, GWL_STYLE);
243  if (style & WS_VISIBLE) {
244  window->flags |= SDL_WINDOW_SHOWN;
245  } else {
246  window->flags &= ~SDL_WINDOW_SHOWN;
247  }
248  if (style & WS_POPUP) {
249  window->flags |= SDL_WINDOW_BORDERLESS;
250  } else {
251  window->flags &= ~SDL_WINDOW_BORDERLESS;
252  }
253  if (style & WS_THICKFRAME) {
254  window->flags |= SDL_WINDOW_RESIZABLE;
255  } else {
256  window->flags &= ~SDL_WINDOW_RESIZABLE;
257  }
258 #ifdef WS_MAXIMIZE
259  if (style & WS_MAXIMIZE) {
260  window->flags |= SDL_WINDOW_MAXIMIZED;
261  } else
262 #endif
263  {
264  window->flags &= ~SDL_WINDOW_MAXIMIZED;
265  }
266 #ifdef WS_MINIMIZE
267  if (style & WS_MINIMIZE) {
268  window->flags |= SDL_WINDOW_MINIMIZED;
269  } else
270 #endif
271  {
272  window->flags &= ~SDL_WINDOW_MINIMIZED;
273  }
274  }
275  if (GetFocus() == hwnd) {
276  window->flags |= SDL_WINDOW_INPUT_FOCUS;
278 
279  if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
280  RECT rect;
281  GetClientRect(hwnd, &rect);
282  ClientToScreen(hwnd, (LPPOINT) & rect);
283  ClientToScreen(hwnd, (LPPOINT) & rect + 1);
284  ClipCursor(&rect);
285  }
286  }
287 
288  /* Enable multi-touch */
289  if (videodata->RegisterTouchWindow) {
290  videodata->RegisterTouchWindow(hwnd, (TWF_FINETOUCH|TWF_WANTPALM));
291  }
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_MINIMIZED) {
339  ShowWindow(hwnd, SW_SHOWMINNOACTIVE);
340  }
341 
342  if (!(window->flags & SDL_WINDOW_OPENGL)) {
343  return 0;
344  }
345 
346  /* The rest of this macro mess is for OpenGL or OpenGL ES windows */
347 #if SDL_VIDEO_OPENGL_ES2
350  && (!_this->gl_data || WIN_GL_UseEGL(_this))
351 #endif /* SDL_VIDEO_OPENGL_WGL */
352  ) {
353 #if SDL_VIDEO_OPENGL_EGL
354  if (WIN_GLES_SetupWindow(_this, window) < 0) {
355  WIN_DestroyWindow(_this, window);
356  return -1;
357  }
358  return 0;
359 #else
360  return SDL_SetError("Could not create GLES window surface (EGL support not configured)");
361 #endif /* SDL_VIDEO_OPENGL_EGL */
362  }
363 #endif /* SDL_VIDEO_OPENGL_ES2 */
364 
365 #if SDL_VIDEO_OPENGL_WGL
366  if (WIN_GL_SetupWindow(_this, window) < 0) {
367  WIN_DestroyWindow(_this, window);
368  return -1;
369  }
370 #else
371  return SDL_SetError("Could not create GL window (WGL support not configured)");
372 #endif
373 
374  return 0;
375 }
376 
377 int
378 WIN_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
379 {
380  HWND hwnd = (HWND) data;
381  LPTSTR title;
382  int titleLen;
383  SDL_bool isstack;
384 
385  /* Query the title from the existing window */
386  titleLen = GetWindowTextLength(hwnd);
387  title = SDL_small_alloc(TCHAR, titleLen + 1, &isstack);
388  if (title) {
389  titleLen = GetWindowText(hwnd, title, titleLen + 1);
390  } else {
391  titleLen = 0;
392  }
393  if (titleLen > 0) {
394  window->title = WIN_StringToUTF8(title);
395  }
396  if (title) {
397  SDL_small_free(title, isstack);
398  }
399 
400  if (SetupWindowData(_this, window, hwnd, GetParent(hwnd), SDL_FALSE) < 0) {
401  return -1;
402  }
403 
404 #if SDL_VIDEO_OPENGL_WGL
405  {
407  if (hint) {
408  /* This hint is a pointer (in string form) of the address of
409  the window to share a pixel format with
410  */
411  SDL_Window *otherWindow = NULL;
412  SDL_sscanf(hint, "%p", (void**)&otherWindow);
413 
414  /* Do some error checking on the pointer */
415  if (otherWindow != NULL && otherWindow->magic == &_this->window_magic) {
416  /* If the otherWindow has SDL_WINDOW_OPENGL set, set it for the new window as well */
417  if (otherWindow->flags & SDL_WINDOW_OPENGL) {
418  window->flags |= SDL_WINDOW_OPENGL;
419  if (!WIN_GL_SetPixelFormatFrom(_this, otherWindow, window)) {
420  return -1;
421  }
422  }
423  }
424  }
425  }
426 #endif
427  return 0;
428 }
429 
430 void
432 {
433  HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
434  LPTSTR title = WIN_UTF8ToString(window->title);
435  SetWindowText(hwnd, title);
436  SDL_free(title);
437 }
438 
439 void
441 {
442  HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
443  HICON hicon = NULL;
444  BYTE *icon_bmp;
445  int icon_len, mask_len, y;
446  SDL_RWops *dst;
447  SDL_bool isstack;
448 
449  /* Create temporary buffer for ICONIMAGE structure */
450  mask_len = (icon->h * (icon->w + 7)/8);
451  icon_len = 40 + icon->h * icon->w * sizeof(Uint32) + mask_len;
452  icon_bmp = SDL_small_alloc(BYTE, icon_len, &isstack);
453  dst = SDL_RWFromMem(icon_bmp, icon_len);
454  if (!dst) {
455  SDL_small_free(icon_bmp, isstack);
456  return;
457  }
458 
459  /* Write the BITMAPINFO header */
460  SDL_WriteLE32(dst, 40);
461  SDL_WriteLE32(dst, icon->w);
462  SDL_WriteLE32(dst, icon->h * 2);
463  SDL_WriteLE16(dst, 1);
464  SDL_WriteLE16(dst, 32);
465  SDL_WriteLE32(dst, BI_RGB);
466  SDL_WriteLE32(dst, icon->h * icon->w * sizeof(Uint32));
467  SDL_WriteLE32(dst, 0);
468  SDL_WriteLE32(dst, 0);
469  SDL_WriteLE32(dst, 0);
470  SDL_WriteLE32(dst, 0);
471 
472  /* Write the pixels upside down into the bitmap buffer */
474  y = icon->h;
475  while (y--) {
476  Uint8 *src = (Uint8 *) icon->pixels + y * icon->pitch;
477  SDL_RWwrite(dst, src, icon->w * sizeof(Uint32), 1);
478  }
479 
480  /* Write the mask */
481  SDL_memset(icon_bmp + icon_len - mask_len, 0xFF, mask_len);
482 
483  hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
484 
485  SDL_RWclose(dst);
486  SDL_small_free(icon_bmp, isstack);
487 
488  /* Set the icon for the window */
489  SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) hicon);
490 
491  /* Set the icon in the task manager (should we do this?) */
492  SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) hicon);
493 }
494 
495 void
497 {
498  WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE);
499 }
500 
501 void
503 {
504  WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOACTIVATE);
505 }
506 
507 int
508 WIN_GetWindowBordersSize(_THIS, SDL_Window * window, int *top, int *left, int *bottom, int *right)
509 {
510  HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
511  RECT rcClient, rcWindow;
512  POINT ptDiff;
513 
514  /* rcClient stores the size of the inner window, while rcWindow stores the outer size relative to the top-left
515  * screen position; so the top/left values of rcClient are always {0,0} and bottom/right are {height,width} */
516  GetClientRect(hwnd, &rcClient);
517  GetWindowRect(hwnd, &rcWindow);
518 
519  /* convert the top/left values to make them relative to
520  * the window; they will end up being slightly negative */
521  ptDiff.y = rcWindow.top;
522  ptDiff.x = rcWindow.left;
523 
524  ScreenToClient(hwnd, &ptDiff);
525 
526  rcWindow.top = ptDiff.y;
527  rcWindow.left = ptDiff.x;
528 
529  /* convert the bottom/right values to make them relative to the window,
530  * these will be slightly bigger than the inner width/height */
531  ptDiff.y = rcWindow.bottom;
532  ptDiff.x = rcWindow.right;
533 
534  ScreenToClient(hwnd, &ptDiff);
535 
536  rcWindow.bottom = ptDiff.y;
537  rcWindow.right = ptDiff.x;
538 
539  /* Now that both the inner and outer rects use the same coordinate system we can substract them to get the border size.
540  * Keep in mind that the top/left coordinates of rcWindow are negative because the border lies slightly before {0,0},
541  * so switch them around because SDL2 wants them in positive. */
542  *top = rcClient.top - rcWindow.top;
543  *left = rcClient.left - rcWindow.left;
544  *bottom = rcWindow.bottom - rcClient.bottom;
545  *right = rcWindow.right - rcClient.right;
546 
547  return 0;
548 }
549 
550 void
552 {
553  DWORD style;
554  HWND hwnd;
555  int nCmdShow;
556 
557  hwnd = ((SDL_WindowData *)window->driverdata)->hwnd;
558  nCmdShow = SW_SHOW;
559  style = GetWindowLong(hwnd, GWL_EXSTYLE);
560  if (style & WS_EX_NOACTIVATE) {
561  nCmdShow = SW_SHOWNOACTIVATE;
562  }
563  ShowWindow(hwnd, nCmdShow);
564 }
565 
566 void
568 {
569  HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
570  ShowWindow(hwnd, SW_HIDE);
571 }
572 
573 void
575 {
576  HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
577  SetForegroundWindow(hwnd);
578 }
579 
580 void
582 {
583  SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
584  HWND hwnd = data->hwnd;
585  data->expected_resize = SDL_TRUE;
586  ShowWindow(hwnd, SW_MAXIMIZE);
587  data->expected_resize = SDL_FALSE;
588 }
589 
590 void
592 {
593  HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
594  ShowWindow(hwnd, SW_MINIMIZE);
595 }
596 
597 void
598 WIN_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
599 {
600  SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
601  HWND hwnd = data->hwnd;
602  DWORD style;
603 
604  style = GetWindowLong(hwnd, GWL_STYLE);
605  style &= ~STYLE_MASK;
606  style |= GetWindowStyle(window);
607 
608  data->in_border_change = SDL_TRUE;
609  SetWindowLong(hwnd, GWL_STYLE, style);
610  WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE);
611  data->in_border_change = SDL_FALSE;
612 }
613 
614 void
615 WIN_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable)
616 {
617  SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
618  HWND hwnd = data->hwnd;
619  DWORD style;
620 
621  style = GetWindowLong(hwnd, GWL_STYLE);
622  style &= ~STYLE_MASK;
623  style |= GetWindowStyle(window);
624 
625  SetWindowLong(hwnd, GWL_STYLE, style);
626 }
627 
628 void
630 {
631  SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
632  HWND hwnd = data->hwnd;
633  data->expected_resize = SDL_TRUE;
634  ShowWindow(hwnd, SW_RESTORE);
635  data->expected_resize = SDL_FALSE;
636 }
637 
638 void
639 WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
640 {
641  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
642  HWND hwnd = data->hwnd;
643  SDL_Rect bounds;
644  DWORD style;
645  HWND top;
646  int x, y;
647  int w, h;
648 
650  top = HWND_TOPMOST;
651  } else {
652  top = HWND_NOTOPMOST;
653  }
654 
655  style = GetWindowLong(hwnd, GWL_STYLE);
656  style &= ~STYLE_MASK;
657  style |= GetWindowStyle(window);
658 
659  WIN_GetDisplayBounds(_this, display, &bounds);
660 
661  if (fullscreen) {
662  x = bounds.x;
663  y = bounds.y;
664  w = bounds.w;
665  h = bounds.h;
666 
667  /* Unset the maximized flag. This fixes
668  https://bugzilla.libsdl.org/show_bug.cgi?id=3215
669  */
670  if (style & WS_MAXIMIZE) {
672  style &= ~WS_MAXIMIZE;
673  }
674  } else {
675  BOOL menu;
676 
677  /* Restore window-maximization state, as applicable.
678  Special care is taken to *not* do this if and when we're
679  alt-tab'ing away (to some other window; as indicated by
680  in_window_deactivation), otherwise
681  https://bugzilla.libsdl.org/show_bug.cgi?id=3215 can reproduce!
682  */
684  style |= WS_MAXIMIZE;
686  }
687 
688  menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
689  WIN_AdjustWindowRectWithStyle(window, style, menu, &x, &y, &w, &h, SDL_FALSE);
690  }
691  SetWindowLong(hwnd, GWL_STYLE, style);
692  data->expected_resize = SDL_TRUE;
693  SetWindowPos(hwnd, top, x, y, w, h, SWP_NOCOPYBITS | SWP_NOACTIVATE);
694  data->expected_resize = SDL_FALSE;
695 }
696 
697 int
698 WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
699 {
700  SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
701  SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
702  HDC hdc;
703  BOOL succeeded = FALSE;
704 
705  hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
706  if (hdc) {
707  succeeded = SetDeviceGammaRamp(hdc, (LPVOID)ramp);
708  if (!succeeded) {
709  WIN_SetError("SetDeviceGammaRamp()");
710  }
711  DeleteDC(hdc);
712  }
713  return succeeded ? 0 : -1;
714 }
715 
716 int
718 {
719  SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
720  SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
721  HDC hdc;
722  BOOL succeeded = FALSE;
723 
724  hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
725  if (hdc) {
726  succeeded = GetDeviceGammaRamp(hdc, (LPVOID)ramp);
727  if (!succeeded) {
728  WIN_SetError("GetDeviceGammaRamp()");
729  }
730  DeleteDC(hdc);
731  }
732  return succeeded ? 0 : -1;
733 }
734 
735 void
736 WIN_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
737 {
738  WIN_UpdateClipCursor(window);
739 
740  if (window->flags & SDL_WINDOW_FULLSCREEN) {
741  UINT flags = SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE;
742 
743  if (!(window->flags & SDL_WINDOW_SHOWN)) {
744  flags |= SWP_NOACTIVATE;
745  }
746  WIN_SetWindowPositionInternal(_this, window, flags);
747  }
748 }
749 
750 void
752 {
753  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
754 
755  if (data) {
756  ReleaseDC(data->hwnd, data->hdc);
757  RemoveProp(data->hwnd, TEXT("SDL_WindowData"));
758  if (data->created) {
759  DestroyWindow(data->hwnd);
760  if (data->parent) {
761  DestroyWindow(data->parent);
762  }
763  } else {
764  /* Restore any original event handler... */
765  if (data->wndproc != NULL) {
766 #ifdef GWLP_WNDPROC
767  SetWindowLongPtr(data->hwnd, GWLP_WNDPROC,
768  (LONG_PTR) data->wndproc);
769 #else
770  SetWindowLong(data->hwnd, GWL_WNDPROC,
771  (LONG_PTR) data->wndproc);
772 #endif
773  }
774  }
775  SDL_free(data);
776  }
777  window->driverdata = NULL;
778 }
779 
780 SDL_bool
782 {
783  const SDL_WindowData *data = (const SDL_WindowData *) window->driverdata;
784  if (info->version.major <= SDL_MAJOR_VERSION) {
785  int versionnum = SDL_VERSIONNUM(info->version.major, info->version.minor, info->version.patch);
786 
788  info->info.win.window = data->hwnd;
789 
790  if (versionnum >= SDL_VERSIONNUM(2, 0, 4)) {
791  info->info.win.hdc = data->hdc;
792  }
793 
794  if (versionnum >= SDL_VERSIONNUM(2, 0, 5)) {
795  info->info.win.hinstance = data->hinstance;
796  }
797 
798  return SDL_TRUE;
799  } else {
800  SDL_SetError("Application not compiled with SDL %d.%d",
802  return SDL_FALSE;
803  }
804 }
805 
806 
807 /*
808  * Creates a HelperWindow used for DirectInput events.
809  */
810 int
811 SDL_HelperWindowCreate(void)
812 {
813  HINSTANCE hInstance = GetModuleHandle(NULL);
814  WNDCLASS wce;
815 
816  /* Make sure window isn't created twice. */
817  if (SDL_HelperWindow != NULL) {
818  return 0;
819  }
820 
821  /* Create the class. */
822  SDL_zero(wce);
823  wce.lpfnWndProc = DefWindowProc;
824  wce.lpszClassName = (LPCWSTR) SDL_HelperWindowClassName;
825  wce.hInstance = hInstance;
826 
827  /* Register the class. */
828  SDL_HelperWindowClass = RegisterClass(&wce);
829  if (SDL_HelperWindowClass == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) {
830  return WIN_SetError("Unable to create Helper Window Class");
831  }
832 
833  /* Create the window. */
834  SDL_HelperWindow = CreateWindowEx(0, SDL_HelperWindowClassName,
835  SDL_HelperWindowName,
836  WS_OVERLAPPED, CW_USEDEFAULT,
837  CW_USEDEFAULT, CW_USEDEFAULT,
838  CW_USEDEFAULT, HWND_MESSAGE, NULL,
839  hInstance, NULL);
840  if (SDL_HelperWindow == NULL) {
841  UnregisterClass(SDL_HelperWindowClassName, hInstance);
842  return WIN_SetError("Unable to create Helper Window");
843  }
844 
845  return 0;
846 }
847 
848 
849 /*
850  * Destroys the HelperWindow previously created with SDL_HelperWindowCreate.
851  */
852 void
853 SDL_HelperWindowDestroy(void)
854 {
855  HINSTANCE hInstance = GetModuleHandle(NULL);
856 
857  /* Destroy the window. */
858  if (SDL_HelperWindow != NULL) {
859  if (DestroyWindow(SDL_HelperWindow) == 0) {
860  WIN_SetError("Unable to destroy Helper Window");
861  return;
862  }
863  SDL_HelperWindow = NULL;
864  }
865 
866  /* Unregister the class. */
867  if (SDL_HelperWindowClass != 0) {
868  if ((UnregisterClass(SDL_HelperWindowClassName, hInstance)) == 0) {
869  WIN_SetError("Unable to destroy Helper Window Class");
870  return;
871  }
872  SDL_HelperWindowClass = 0;
873  }
874 }
875 
876 void WIN_OnWindowEnter(_THIS, SDL_Window * window)
877 {
878  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
879 
880  if (!data || !data->hwnd) {
881  /* The window wasn't fully initialized */
882  return;
883  }
884 
885  if (window->flags & SDL_WINDOW_ALWAYS_ON_TOP) {
886  WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE);
887  }
888 
889 #ifdef WM_MOUSELEAVE
890  {
891  TRACKMOUSEEVENT trackMouseEvent;
892 
893  trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
894  trackMouseEvent.dwFlags = TME_LEAVE;
895  trackMouseEvent.hwndTrack = data->hwnd;
896 
897  TrackMouseEvent(&trackMouseEvent);
898  }
899 #endif /* WM_MOUSELEAVE */
900 }
901 
902 void
904 {
905  SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
906  SDL_Mouse *mouse = SDL_GetMouse();
907  RECT rect;
908 
909  if (data->in_title_click || data->focus_click_pending) {
910  return;
911  }
912  if (data->skip_update_clipcursor) {
914  return;
915  }
916 
917  if ((mouse->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
918  (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
919  if (mouse->relative_mode && !mouse->relative_mode_warp) {
920  LONG cx, cy;
921  GetWindowRect(data->hwnd, &rect);
922 
923  cx = (rect.left + rect.right) / 2;
924  cy = (rect.top + rect.bottom) / 2;
925 
926  /* Make an absurdly small clip rect */
927  rect.left = cx - 1;
928  rect.right = cx + 1;
929  rect.top = cy - 1;
930  rect.bottom = cy + 1;
931 
932  if (ClipCursor(&rect)) {
933  data->cursor_clipped_rect = rect;
934  }
935  } else {
936  if (GetClientRect(data->hwnd, &rect) && !IsRectEmpty(&rect)) {
937  ClientToScreen(data->hwnd, (LPPOINT) & rect);
938  ClientToScreen(data->hwnd, (LPPOINT) & rect + 1);
939  if (ClipCursor(&rect)) {
940  data->cursor_clipped_rect = rect;
941  }
942  }
943  }
944  } else if (GetClipCursor(&rect) && SDL_memcmp(&rect, &data->cursor_clipped_rect, sizeof(rect)) == 0) {
945  ClipCursor(NULL);
947  }
948 }
949 
950 int
952 {
953  return 0; /* just succeed, the real work is done elsewhere. */
954 }
955 
956 int
957 WIN_SetWindowOpacity(_THIS, SDL_Window * window, float opacity)
958 {
959  const SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
960  const HWND hwnd = data->hwnd;
961  const LONG style = GetWindowLong(hwnd, GWL_EXSTYLE);
962 
963  SDL_assert(style != 0);
964 
965  if (opacity == 1.0f) {
966  /* want it fully opaque, just mark it unlayered if necessary. */
967  if (style & WS_EX_LAYERED) {
968  if (SetWindowLong(hwnd, GWL_EXSTYLE, style & ~WS_EX_LAYERED) == 0) {
969  return WIN_SetError("SetWindowLong()");
970  }
971  }
972  } else {
973  const BYTE alpha = (BYTE) ((int) (opacity * 255.0f));
974  /* want it transparent, mark it layered if necessary. */
975  if ((style & WS_EX_LAYERED) == 0) {
976  if (SetWindowLong(hwnd, GWL_EXSTYLE, style | WS_EX_LAYERED) == 0) {
977  return WIN_SetError("SetWindowLong()");
978  }
979  }
980 
981  if (SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA) == 0) {
982  return WIN_SetError("SetLayeredWindowAttributes()");
983  }
984  }
985 
986  return 0;
987 }
988 
989 void
990 WIN_AcceptDragAndDrop(SDL_Window * window, SDL_bool accept)
991 {
992  const SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
993  DragAcceptFiles(data->hwnd, accept ? TRUE : FALSE);
994 }
995 
996 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
997 
998 /* 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:178
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_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:70
void WIN_MaximizeWindow(_THIS, SDL_Window *window)
#define SDL_GetHint
SDL_version version
Definition: SDL_syswm.h:199
SDL_bool expected_resize
Uint8 major
Definition: SDL_version.h:53
#define SDL_WriteLE16
uint16_t Uint16
Definition: SDL_stdinc.h:191
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:200
SDL_Window * window
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:382
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)
void WIN_AcceptDragAndDrop(SDL_Window *window, SDL_bool accept)
static SDL_VideoDevice * _this
Definition: SDL_video.c:118
#define SDL_small_alloc(type, count, pisstack)
Definition: SDL_internal.h:39
SDL_bool windowed_mode_was_maximized
TCHAR DeviceName[32]
SDL_bool in_border_change
int WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)
#define SDL_RWwrite
void WIN_SetWindowResizable(_THIS, SDL_Window *window, SDL_bool resizable)
void * pixels
Definition: SDL_surface.h:76
void WIN_MinimizeWindow(_THIS, SDL_Window *window)
#define _THIS
struct SDL_VideoData * videodata
uint8_t Uint8
Definition: SDL_stdinc.h:179
#define SDL_free
#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)
#define SDL_memcmp
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:695
#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:79
#define SDL_VIDEO_OPENGL_WGL
#define TWF_FINETOUCH
#define TWF_WANTPALM
int w
Definition: SDL_rect.h:80
void WIN_RestoreWindow(_THIS, SDL_Window *window)
SDL_bool skip_update_clipcursor
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:221
SDL_bool SDL_ShouldAllowTopmost(void)
Definition: SDL_video.c:3992
#define NULL
Definition: begin_code.h:167
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:161
SDL_PixelFormat * format
Definition: SDL_surface.h:73
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:1089
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
void WIN_SetWindowGrab(_THIS, SDL_Window *window, SDL_bool grabbed)
int h
Definition: SDL_rect.h:80
The type used to identify a window.
Definition: SDL_sysvideo.h:73
union SDL_SysWMinfo::@17 info
uint32_t Uint32
Definition: SDL_stdinc.h:203
#define SDL_small_free(ptr, isstack)
Definition: SDL_internal.h:40
void WIN_SetWindowFullscreen(_THIS, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen)
#define SDL_WriteLE32
#define SDL_RWclose
SDL_bool in_window_deactivation
void WIN_SetWindowBordered(_THIS, SDL_Window *window, SDL_bool bordered)
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)
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:79
SDL_bool in_title_click
#define SDL_memset
A rectangle, with the origin at the upper left (integer).
Definition: SDL_rect.h:77
GLint left
Uint8 patch
Definition: SDL_version.h:55
struct SDL_VideoDevice::@262 gl_config