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