Atlas - SDL_windowswindow.c
Home / ext / SDL2 / src / video / windows Lines: 1 | Size: 30981 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 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. */ 49HWND SDL_HelperWindow = NULL; 50static WCHAR *SDL_HelperWindowClassName = TEXT("SDLHelperWindowInputCatcher"); 51static WCHAR *SDL_HelperWindowName = TEXT("SDLHelperWindowInputMsgWindow"); 52static 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 69static DWORD 70GetWindowStyle(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 109static void 110WIN_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 131static void 132WIN_AdjustWindowRect(SDL_Window *window, int *x, int *y, int *width, int *height, SDL_bool use_current) 133{ 134 SDL_WindowData *data = (SDL_WindowData *)window->driverdata; 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 144static void 145WIN_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 */ 154 if (SDL_ShouldAllowTopmost() && ((window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS) || (window->flags & SDL_WINDOW_ALWAYS_ON_TOP))) { 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 167static int 168SetupWindowData(_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; 277 SDL_SetKeyboardFocus(data->window); 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 301int 302WIN_CreateWindow(_THIS, SDL_Window * window) 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 325 WIN_PumpEvents(_this); 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 348 if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES 349#if SDL_VIDEO_OPENGL_WGL 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 377int 378WIN_CreateWindowFrom(_THIS, SDL_Window * window, const void *data) 379{ 380 HWND hwnd = (HWND) data; 381 LPTSTR title; 382 int titleLen; 383 384 /* Query the title from the existing window */ 385 titleLen = GetWindowTextLength(hwnd); 386 title = SDL_stack_alloc(TCHAR, titleLen + 1); 387 if (title) { 388 titleLen = GetWindowText(hwnd, title, titleLen); 389 } else { 390 titleLen = 0; 391 } 392 if (titleLen > 0) { 393 window->title = WIN_StringToUTF8(title); 394 } 395 if (title) { 396 SDL_stack_free(title); 397 } 398 399 if (SetupWindowData(_this, window, hwnd, GetParent(hwnd), SDL_FALSE) < 0) { 400 return -1; 401 } 402 403#if SDL_VIDEO_OPENGL_WGL 404 { 405 const char *hint = SDL_GetHint(SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT); 406 if (hint) { 407 /* This hint is a pointer (in string form) of the address of 408 the window to share a pixel format with 409 */ 410 SDL_Window *otherWindow = NULL; 411 SDL_sscanf(hint, "%p", (void**)&otherWindow); 412 413 /* Do some error checking on the pointer */ 414 if (otherWindow != NULL && otherWindow->magic == &_this->window_magic) { 415 /* If the otherWindow has SDL_WINDOW_OPENGL set, set it for the new window as well */ 416 if (otherWindow->flags & SDL_WINDOW_OPENGL) { 417 window->flags |= SDL_WINDOW_OPENGL; 418 if (!WIN_GL_SetPixelFormatFrom(_this, otherWindow, window)) { 419 return -1; 420 } 421 } 422 } 423 } 424 } 425#endif 426 return 0; 427} 428 429void 430WIN_SetWindowTitle(_THIS, SDL_Window * window) 431{ 432 HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; 433 LPTSTR title = WIN_UTF8ToString(window->title); 434 SetWindowText(hwnd, title); 435 SDL_free(title); 436} 437 438void 439WIN_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon) 440{ 441 HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; 442 HICON hicon = NULL; 443 BYTE *icon_bmp; 444 int icon_len, mask_len, y; 445 SDL_RWops *dst; 446 447 /* Create temporary buffer for ICONIMAGE structure */ 448 mask_len = (icon->h * (icon->w + 7)/8); 449 icon_len = 40 + icon->h * icon->w * sizeof(Uint32) + mask_len; 450 icon_bmp = SDL_stack_alloc(BYTE, icon_len); 451 dst = SDL_RWFromMem(icon_bmp, icon_len); 452 if (!dst) { 453 SDL_stack_free(icon_bmp); 454 return; 455 } 456 457 /* Write the BITMAPINFO header */ 458 SDL_WriteLE32(dst, 40); 459 SDL_WriteLE32(dst, icon->w); 460 SDL_WriteLE32(dst, icon->h * 2); 461 SDL_WriteLE16(dst, 1); 462 SDL_WriteLE16(dst, 32); 463 SDL_WriteLE32(dst, BI_RGB); 464 SDL_WriteLE32(dst, icon->h * icon->w * sizeof(Uint32)); 465 SDL_WriteLE32(dst, 0); 466 SDL_WriteLE32(dst, 0); 467 SDL_WriteLE32(dst, 0); 468 SDL_WriteLE32(dst, 0); 469 470 /* Write the pixels upside down into the bitmap buffer */ 471 SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888); 472 y = icon->h; 473 while (y--) { 474 Uint8 *src = (Uint8 *) icon->pixels + y * icon->pitch; 475 SDL_RWwrite(dst, src, icon->w * sizeof(Uint32), 1); 476 } 477 478 /* Write the mask */ 479 SDL_memset(icon_bmp + icon_len - mask_len, 0xFF, mask_len); 480 481 hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000); 482 483 SDL_RWclose(dst); 484 SDL_stack_free(icon_bmp); 485 486 /* Set the icon for the window */ 487 SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) hicon); 488 489 /* Set the icon in the task manager (should we do this?) */ 490 SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) hicon); 491} 492 493void 494WIN_SetWindowPosition(_THIS, SDL_Window * window) 495{ 496 WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE); 497} 498 499void 500WIN_SetWindowSize(_THIS, SDL_Window * window) 501{ 502 WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOACTIVATE); 503} 504 505int 506WIN_GetWindowBordersSize(_THIS, SDL_Window * window, int *top, int *left, int *bottom, int *right) 507{ 508 HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; 509 RECT rcClient, rcWindow; 510 POINT ptDiff; 511 512 /* rcClient stores the size of the inner window, while rcWindow stores the outer size relative to the top-left 513 * screen position; so the top/left values of rcClient are always {0,0} and bottom/right are {height,width} */ 514 GetClientRect(hwnd, &rcClient); 515 GetWindowRect(hwnd, &rcWindow); 516 517 /* convert the top/left values to make them relative to 518 * the window; they will end up being slightly negative */ 519 ptDiff.y = rcWindow.top; 520 ptDiff.x = rcWindow.left; 521 522 ScreenToClient(hwnd, &ptDiff); 523 524 rcWindow.top = ptDiff.y; 525 rcWindow.left = ptDiff.x; 526 527 /* convert the bottom/right values to make them relative to the window, 528 * these will be slightly bigger than the inner width/height */ 529 ptDiff.y = rcWindow.bottom; 530 ptDiff.x = rcWindow.right; 531 532 ScreenToClient(hwnd, &ptDiff); 533 534 rcWindow.bottom = ptDiff.y; 535 rcWindow.right = ptDiff.x; 536 537 /* Now that both the inner and outer rects use the same coordinate system we can substract them to get the border size. 538 * Keep in mind that the top/left coordinates of rcWindow are negative because the border lies slightly before {0,0}, 539 * so switch them around because SDL2 wants them in positive. */ 540 *top = rcClient.top - rcWindow.top; 541 *left = rcClient.left - rcWindow.left; 542 *bottom = rcWindow.bottom - rcClient.bottom; 543 *right = rcWindow.right - rcClient.right; 544 545 return 0; 546} 547 548void 549WIN_ShowWindow(_THIS, SDL_Window * window) 550{ 551 DWORD style; 552 HWND hwnd; 553 int nCmdShow; 554 555 hwnd = ((SDL_WindowData *)window->driverdata)->hwnd; 556 nCmdShow = SW_SHOW; 557 style = GetWindowLong(hwnd, GWL_EXSTYLE); 558 if (style & WS_EX_NOACTIVATE) { 559 nCmdShow = SW_SHOWNOACTIVATE; 560 } 561 ShowWindow(hwnd, nCmdShow); 562} 563 564void 565WIN_HideWindow(_THIS, SDL_Window * window) 566{ 567 HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; 568 ShowWindow(hwnd, SW_HIDE); 569} 570 571void 572WIN_RaiseWindow(_THIS, SDL_Window * window) 573{ 574 HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; 575 SetForegroundWindow(hwnd); 576} 577 578void 579WIN_MaximizeWindow(_THIS, SDL_Window * window) 580{ 581 SDL_WindowData *data = (SDL_WindowData *)window->driverdata; 582 HWND hwnd = data->hwnd; 583 data->expected_resize = SDL_TRUE; 584 ShowWindow(hwnd, SW_MAXIMIZE); 585 data->expected_resize = SDL_FALSE; 586} 587 588void 589WIN_MinimizeWindow(_THIS, SDL_Window * window) 590{ 591 HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; 592 ShowWindow(hwnd, SW_MINIMIZE); 593} 594 595void 596WIN_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered) 597{ 598 SDL_WindowData *data = (SDL_WindowData *)window->driverdata; 599 HWND hwnd = data->hwnd; 600 DWORD style; 601 602 style = GetWindowLong(hwnd, GWL_STYLE); 603 style &= ~STYLE_MASK; 604 style |= GetWindowStyle(window); 605 606 data->in_border_change = SDL_TRUE; 607 SetWindowLong(hwnd, GWL_STYLE, style); 608 WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE); 609 data->in_border_change = SDL_FALSE; 610} 611 612void 613WIN_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable) 614{ 615 SDL_WindowData *data = (SDL_WindowData *)window->driverdata; 616 HWND hwnd = data->hwnd; 617 DWORD style; 618 619 style = GetWindowLong(hwnd, GWL_STYLE); 620 style &= ~STYLE_MASK; 621 style |= GetWindowStyle(window); 622 623 SetWindowLong(hwnd, GWL_STYLE, style); 624} 625 626void 627WIN_RestoreWindow(_THIS, SDL_Window * window) 628{ 629 SDL_WindowData *data = (SDL_WindowData *)window->driverdata; 630 HWND hwnd = data->hwnd; 631 data->expected_resize = SDL_TRUE; 632 ShowWindow(hwnd, SW_RESTORE); 633 data->expected_resize = SDL_FALSE; 634} 635 636void 637WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen) 638{ 639 SDL_WindowData *data = (SDL_WindowData *) window->driverdata; 640 HWND hwnd = data->hwnd; 641 SDL_Rect bounds; 642 DWORD style; 643 HWND top; 644 int x, y; 645 int w, h; 646 647 if (SDL_ShouldAllowTopmost() && ((window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS) || window->flags & SDL_WINDOW_ALWAYS_ON_TOP)) { 648 top = HWND_TOPMOST; 649 } else { 650 top = HWND_NOTOPMOST; 651 } 652 653 style = GetWindowLong(hwnd, GWL_STYLE); 654 style &= ~STYLE_MASK; 655 style |= GetWindowStyle(window); 656 657 WIN_GetDisplayBounds(_this, display, &bounds); 658 659 if (fullscreen) { 660 x = bounds.x; 661 y = bounds.y; 662 w = bounds.w; 663 h = bounds.h; 664 665 /* Unset the maximized flag. This fixes 666 https://bugzilla.libsdl.org/show_bug.cgi?id=3215 667 */ 668 if (style & WS_MAXIMIZE) { 669 data->windowed_mode_was_maximized = SDL_TRUE; 670 style &= ~WS_MAXIMIZE; 671 } 672 } else { 673 BOOL menu; 674 675 /* Restore window-maximization state, as applicable. 676 Special care is taken to *not* do this if and when we're 677 alt-tab'ing away (to some other window; as indicated by 678 in_window_deactivation), otherwise 679 https://bugzilla.libsdl.org/show_bug.cgi?id=3215 can reproduce! 680 */ 681 if (data->windowed_mode_was_maximized && !data->in_window_deactivation) { 682 style |= WS_MAXIMIZE; 683 data->windowed_mode_was_maximized = SDL_FALSE; 684 } 685 686 menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL); 687 WIN_AdjustWindowRectWithStyle(window, style, menu, &x, &y, &w, &h, SDL_FALSE); 688 } 689 SetWindowLong(hwnd, GWL_STYLE, style); 690 data->expected_resize = SDL_TRUE; 691 SetWindowPos(hwnd, top, x, y, w, h, SWP_NOCOPYBITS | SWP_NOACTIVATE); 692 data->expected_resize = SDL_FALSE; 693} 694 695int 696WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp) 697{ 698 SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); 699 SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata; 700 HDC hdc; 701 BOOL succeeded = FALSE; 702 703 hdc = CreateDC(data->DeviceName, NULL, NULL, NULL); 704 if (hdc) { 705 succeeded = SetDeviceGammaRamp(hdc, (LPVOID)ramp); 706 if (!succeeded) { 707 WIN_SetError("SetDeviceGammaRamp()"); 708 } 709 DeleteDC(hdc); 710 } 711 return succeeded ? 0 : -1; 712} 713 714int 715WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp) 716{ 717 SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); 718 SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata; 719 HDC hdc; 720 BOOL succeeded = FALSE; 721 722 hdc = CreateDC(data->DeviceName, NULL, NULL, NULL); 723 if (hdc) { 724 succeeded = GetDeviceGammaRamp(hdc, (LPVOID)ramp); 725 if (!succeeded) { 726 WIN_SetError("GetDeviceGammaRamp()"); 727 } 728 DeleteDC(hdc); 729 } 730 return succeeded ? 0 : -1; 731} 732 733void 734WIN_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed) 735{ 736 WIN_UpdateClipCursor(window); 737 738 if (window->flags & SDL_WINDOW_FULLSCREEN) { 739 UINT flags = SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE; 740 741 if (!(window->flags & SDL_WINDOW_SHOWN)) { 742 flags |= SWP_NOACTIVATE; 743 } 744 WIN_SetWindowPositionInternal(_this, window, flags); 745 } 746} 747 748void 749WIN_DestroyWindow(_THIS, SDL_Window * window) 750{ 751 SDL_WindowData *data = (SDL_WindowData *) window->driverdata; 752 753 if (data) { 754 ReleaseDC(data->hwnd, data->hdc); 755 RemoveProp(data->hwnd, TEXT("SDL_WindowData")); 756 if (data->created) { 757 DestroyWindow(data->hwnd); 758 if (data->parent) { 759 DestroyWindow(data->parent); 760 } 761 } else { 762 /* Restore any original event handler... */ 763 if (data->wndproc != NULL) { 764#ifdef GWLP_WNDPROC 765 SetWindowLongPtr(data->hwnd, GWLP_WNDPROC, 766 (LONG_PTR) data->wndproc); 767#else 768 SetWindowLong(data->hwnd, GWL_WNDPROC, 769 (LONG_PTR) data->wndproc); 770#endif 771 } 772 } 773 SDL_free(data); 774 } 775 window->driverdata = NULL; 776} 777 778SDL_bool 779WIN_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) 780{ 781 const SDL_WindowData *data = (const SDL_WindowData *) window->driverdata; 782 if (info->version.major <= SDL_MAJOR_VERSION) { 783 int versionnum = SDL_VERSIONNUM(info->version.major, info->version.minor, info->version.patch); 784 785 info->subsystem = SDL_SYSWM_WINDOWS; 786 info->info.win.window = data->hwnd; 787 788 if (versionnum >= SDL_VERSIONNUM(2, 0, 4)) { 789 info->info.win.hdc = data->hdc; 790 } 791 792 if (versionnum >= SDL_VERSIONNUM(2, 0, 5)) { 793 info->info.win.hinstance = data->hinstance; 794 } 795 796 return SDL_TRUE; 797 } else { 798 SDL_SetError("Application not compiled with SDL %d.%d", 799 SDL_MAJOR_VERSION, SDL_MINOR_VERSION); 800 return SDL_FALSE; 801 } 802} 803 804 805/* 806 * Creates a HelperWindow used for DirectInput events. 807 */ 808int 809SDL_HelperWindowCreate(void) 810{ 811 HINSTANCE hInstance = GetModuleHandle(NULL); 812 WNDCLASS wce; 813 814 /* Make sure window isn't created twice. */ 815 if (SDL_HelperWindow != NULL) { 816 return 0; 817 } 818 819 /* Create the class. */ 820 SDL_zero(wce); 821 wce.lpfnWndProc = DefWindowProc; 822 wce.lpszClassName = (LPCWSTR) SDL_HelperWindowClassName; 823 wce.hInstance = hInstance; 824 825 /* Register the class. */ 826 SDL_HelperWindowClass = RegisterClass(&wce); 827 if (SDL_HelperWindowClass == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) { 828 return WIN_SetError("Unable to create Helper Window Class"); 829 } 830 831 /* Create the window. */ 832 SDL_HelperWindow = CreateWindowEx(0, SDL_HelperWindowClassName, 833 SDL_HelperWindowName, 834 WS_OVERLAPPED, CW_USEDEFAULT, 835 CW_USEDEFAULT, CW_USEDEFAULT, 836 CW_USEDEFAULT, HWND_MESSAGE, NULL, 837 hInstance, NULL); 838 if (SDL_HelperWindow == NULL) { 839 UnregisterClass(SDL_HelperWindowClassName, hInstance); 840 return WIN_SetError("Unable to create Helper Window"); 841 } 842 843 return 0; 844} 845 846 847/* 848 * Destroys the HelperWindow previously created with SDL_HelperWindowCreate. 849 */ 850void 851SDL_HelperWindowDestroy(void) 852{ 853 HINSTANCE hInstance = GetModuleHandle(NULL); 854 855 /* Destroy the window. */ 856 if (SDL_HelperWindow != NULL) { 857 if (DestroyWindow(SDL_HelperWindow) == 0) { 858 WIN_SetError("Unable to destroy Helper Window"); 859 return; 860 } 861 SDL_HelperWindow = NULL; 862 } 863 864 /* Unregister the class. */ 865 if (SDL_HelperWindowClass != 0) { 866 if ((UnregisterClass(SDL_HelperWindowClassName, hInstance)) == 0) { 867 WIN_SetError("Unable to destroy Helper Window Class"); 868 return; 869 } 870 SDL_HelperWindowClass = 0; 871 } 872} 873 874void WIN_OnWindowEnter(_THIS, SDL_Window * window) 875{ 876 SDL_WindowData *data = (SDL_WindowData *) window->driverdata; 877 878 if (!data || !data->hwnd) { 879 /* The window wasn't fully initialized */ 880 return; 881 } 882 883 if (window->flags & SDL_WINDOW_ALWAYS_ON_TOP) { 884 WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE); 885 } 886 887#ifdef WM_MOUSELEAVE 888 { 889 TRACKMOUSEEVENT trackMouseEvent; 890 891 trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); 892 trackMouseEvent.dwFlags = TME_LEAVE; 893 trackMouseEvent.hwndTrack = data->hwnd; 894 895 TrackMouseEvent(&trackMouseEvent); 896 } 897#endif /* WM_MOUSELEAVE */ 898} 899 900void 901WIN_UpdateClipCursor(SDL_Window *window) 902{ 903 SDL_WindowData *data = (SDL_WindowData *) window->driverdata; 904 SDL_Mouse *mouse = SDL_GetMouse(); 905 RECT rect; 906 907 if (data->focus_click_pending) { 908 return; 909 } 910 911 if ((mouse->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) && 912 (window->flags & SDL_WINDOW_INPUT_FOCUS)) { 913 if (mouse->relative_mode && !mouse->relative_mode_warp) { 914 LONG cx, cy; 915 GetWindowRect(data->hwnd, &rect); 916 917 cx = (rect.left + rect.right) / 2; 918 cy = (rect.top + rect.bottom) / 2; 919 920 /* Make an absurdly small clip rect */ 921 rect.left = cx - 1; 922 rect.right = cx + 1; 923 rect.top = cy - 1; 924 rect.bottom = cy + 1; 925 926 if (ClipCursor(&rect)) { 927 data->cursor_clipped_rect = rect; 928 } 929 } else { 930 if (GetClientRect(data->hwnd, &rect) && !IsRectEmpty(&rect)) { 931 ClientToScreen(data->hwnd, (LPPOINT) & rect); 932 ClientToScreen(data->hwnd, (LPPOINT) & rect + 1); 933 if (ClipCursor(&rect)) { 934 data->cursor_clipped_rect = rect; 935 } 936 } 937 } 938 } else if (GetClipCursor(&rect) && SDL_memcmp(&rect, &data->cursor_clipped_rect, sizeof(rect)) == 0) { 939 ClipCursor(NULL); 940 SDL_zero(data->cursor_clipped_rect); 941 } 942} 943 944int 945WIN_SetWindowHitTest(SDL_Window *window, SDL_bool enabled) 946{ 947 return 0; /* just succeed, the real work is done elsewhere. */ 948} 949 950int 951WIN_SetWindowOpacity(_THIS, SDL_Window * window, float opacity) 952{ 953 const SDL_WindowData *data = (SDL_WindowData *) window->driverdata; 954 const HWND hwnd = data->hwnd; 955 const LONG style = GetWindowLong(hwnd, GWL_EXSTYLE); 956 957 SDL_assert(style != 0); 958 959 if (opacity == 1.0f) { 960 /* want it fully opaque, just mark it unlayered if necessary. */ 961 if (style & WS_EX_LAYERED) { 962 if (SetWindowLong(hwnd, GWL_EXSTYLE, style & ~WS_EX_LAYERED) == 0) { 963 return WIN_SetError("SetWindowLong()"); 964 } 965 } 966 } else { 967 const BYTE alpha = (BYTE) ((int) (opacity * 255.0f)); 968 /* want it transparent, mark it layered if necessary. */ 969 if ((style & WS_EX_LAYERED) == 0) { 970 if (SetWindowLong(hwnd, GWL_EXSTYLE, style | WS_EX_LAYERED) == 0) { 971 return WIN_SetError("SetWindowLong()"); 972 } 973 } 974 975 if (SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA) == 0) { 976 return WIN_SetError("SetLayeredWindowAttributes()"); 977 } 978 } 979 980 return 0; 981} 982 983void 984WIN_AcceptDragAndDrop(SDL_Window * window, SDL_bool accept) 985{ 986 const SDL_WindowData *data = (SDL_WindowData *) window->driverdata; 987 DragAcceptFiles(data->hwnd, accept ? TRUE : FALSE); 988} 989 990#endif /* SDL_VIDEO_DRIVER_WINDOWS */ 991 992/* vi: set ts=4 sw=4 expandtab: */ 993[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.