Atlas - SDL_winrtvideo.cpp

Home / ext / SDL2 / src / video / winrt Lines: 1 | Size: 30636 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_WINRT 24 25/* WinRT SDL video driver implementation 26 27 Initial work on this was done by David Ludwig ([email protected]), and 28 was based off of SDL's "dummy" video driver. 29 */ 30 31/* Windows includes */ 32#include <agile.h> 33#include <windows.graphics.display.h> 34#include <windows.system.display.h> 35#include <dxgi.h> 36#include <dxgi1_2.h> 37using namespace Windows::ApplicationModel::Core; 38using namespace Windows::Foundation; 39using namespace Windows::Graphics::Display; 40using namespace Windows::UI::Core; 41using namespace Windows::UI::ViewManagement; 42 43 44/* [re]declare Windows GUIDs locally, to limit the amount of external lib(s) SDL has to link to */ 45static const GUID IID_IDisplayRequest = { 0xe5732044, 0xf49f, 0x4b60, { 0x8d, 0xd4, 0x5e, 0x7e, 0x3a, 0x63, 0x2a, 0xc0 } }; 46static const GUID IID_IDXGIFactory2 = { 0x50c83a1c, 0xe072, 0x4c48, { 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } }; 47 48 49/* SDL includes */ 50extern "C" { 51#include "SDL_video.h" 52#include "SDL_mouse.h" 53#include "../SDL_sysvideo.h" 54#include "../SDL_pixels_c.h" 55#include "../../events/SDL_events_c.h" 56#include "../../render/SDL_sysrender.h" 57#include "SDL_syswm.h" 58#include "SDL_winrtopengles.h" 59#include "../../core/windows/SDL_windows.h" 60} 61 62#include "../../core/winrt/SDL_winrtapp_direct3d.h" 63#include "../../core/winrt/SDL_winrtapp_xaml.h" 64#include "SDL_winrtvideo_cpp.h" 65#include "SDL_winrtevents_c.h" 66#include "SDL_winrtgamebar_cpp.h" 67#include "SDL_winrtmouse_c.h" 68#include "SDL_main.h" 69#include "SDL_system.h" 70//#include "SDL_log.h" 71 72 73/* Initialization/Query functions */ 74static int WINRT_VideoInit(_THIS); 75static int WINRT_InitModes(_THIS); 76static int WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode); 77static void WINRT_VideoQuit(_THIS); 78 79 80/* Window functions */ 81static int WINRT_CreateWindow(_THIS, SDL_Window * window); 82static void WINRT_SetWindowSize(_THIS, SDL_Window * window); 83static void WINRT_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen); 84static void WINRT_DestroyWindow(_THIS, SDL_Window * window); 85static SDL_bool WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info); 86 87 88/* Misc functions */ 89static ABI::Windows::System::Display::IDisplayRequest * WINRT_CreateDisplayRequest(_THIS); 90extern void WINRT_SuspendScreenSaver(_THIS); 91 92 93/* SDL-internal globals: */ 94SDL_Window * WINRT_GlobalSDLWindow = NULL; 95 96 97/* WinRT driver bootstrap functions */ 98 99static int 100WINRT_Available(void) 101{ 102 return (1); 103} 104 105static void 106WINRT_DeleteDevice(SDL_VideoDevice * device) 107{ 108 if (device->driverdata) { 109 SDL_VideoData * video_data = (SDL_VideoData *)device->driverdata; 110 if (video_data->winrtEglWindow) { 111 video_data->winrtEglWindow->Release(); 112 } 113 SDL_free(video_data); 114 } 115 116 SDL_free(device); 117} 118 119static SDL_VideoDevice * 120WINRT_CreateDevice(int devindex) 121{ 122 SDL_VideoDevice *device; 123 SDL_VideoData *data; 124 125 /* Initialize all variables that we clean on shutdown */ 126 device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice)); 127 if (!device) { 128 SDL_OutOfMemory(); 129 return (0); 130 } 131 132 data = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData)); 133 if (!data) { 134 SDL_OutOfMemory(); 135 SDL_free(device); 136 return (0); 137 } 138 device->driverdata = data; 139 140 /* Set the function pointers */ 141 device->VideoInit = WINRT_VideoInit; 142 device->VideoQuit = WINRT_VideoQuit; 143 device->CreateSDLWindow = WINRT_CreateWindow; 144 device->SetWindowSize = WINRT_SetWindowSize; 145 device->SetWindowFullscreen = WINRT_SetWindowFullscreen; 146 device->DestroyWindow = WINRT_DestroyWindow; 147 device->SetDisplayMode = WINRT_SetDisplayMode; 148 device->PumpEvents = WINRT_PumpEvents; 149 device->GetWindowWMInfo = WINRT_GetWindowWMInfo; 150 device->SuspendScreenSaver = WINRT_SuspendScreenSaver; 151 152#if NTDDI_VERSION >= NTDDI_WIN10 153 device->HasScreenKeyboardSupport = WINRT_HasScreenKeyboardSupport; 154 device->ShowScreenKeyboard = WINRT_ShowScreenKeyboard; 155 device->HideScreenKeyboard = WINRT_HideScreenKeyboard; 156 device->IsScreenKeyboardShown = WINRT_IsScreenKeyboardShown; 157#endif 158 159#ifdef SDL_VIDEO_OPENGL_EGL 160 device->GL_LoadLibrary = WINRT_GLES_LoadLibrary; 161 device->GL_GetProcAddress = WINRT_GLES_GetProcAddress; 162 device->GL_UnloadLibrary = WINRT_GLES_UnloadLibrary; 163 device->GL_CreateContext = WINRT_GLES_CreateContext; 164 device->GL_MakeCurrent = WINRT_GLES_MakeCurrent; 165 device->GL_SetSwapInterval = WINRT_GLES_SetSwapInterval; 166 device->GL_GetSwapInterval = WINRT_GLES_GetSwapInterval; 167 device->GL_SwapWindow = WINRT_GLES_SwapWindow; 168 device->GL_DeleteContext = WINRT_GLES_DeleteContext; 169#endif 170 device->free = WINRT_DeleteDevice; 171 172 return device; 173} 174 175#define WINRTVID_DRIVER_NAME "winrt" 176VideoBootStrap WINRT_bootstrap = { 177 WINRTVID_DRIVER_NAME, "SDL WinRT video driver", 178 WINRT_Available, WINRT_CreateDevice 179}; 180 181int 182WINRT_VideoInit(_THIS) 183{ 184 SDL_VideoData * driverdata = (SDL_VideoData *) _this->driverdata; 185 if (WINRT_InitModes(_this) < 0) { 186 return -1; 187 } 188 WINRT_InitMouse(_this); 189 WINRT_InitTouch(_this); 190 WINRT_InitGameBar(_this); 191 if (driverdata) { 192 /* Initialize screensaver-disabling support */ 193 driverdata->displayRequest = WINRT_CreateDisplayRequest(_this); 194 } 195 return 0; 196} 197 198extern "C" 199Uint32 D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat); 200 201static void 202WINRT_DXGIModeToSDLDisplayMode(const DXGI_MODE_DESC * dxgiMode, SDL_DisplayMode * sdlMode) 203{ 204 SDL_zerop(sdlMode); 205 sdlMode->w = dxgiMode->Width; 206 sdlMode->h = dxgiMode->Height; 207 sdlMode->refresh_rate = dxgiMode->RefreshRate.Numerator / dxgiMode->RefreshRate.Denominator; 208 sdlMode->format = D3D11_DXGIFormatToSDLPixelFormat(dxgiMode->Format); 209} 210 211static int 212WINRT_AddDisplaysForOutput (_THIS, IDXGIAdapter1 * dxgiAdapter1, int outputIndex) 213{ 214 HRESULT hr; 215 IDXGIOutput * dxgiOutput = NULL; 216 DXGI_OUTPUT_DESC dxgiOutputDesc; 217 SDL_VideoDisplay display; 218 char * displayName = NULL; 219 UINT numModes; 220 DXGI_MODE_DESC * dxgiModes = NULL; 221 int functionResult = -1; /* -1 for failure, 0 for success */ 222 DXGI_MODE_DESC modeToMatch, closestMatch; 223 224 SDL_zero(display); 225 226 hr = dxgiAdapter1->EnumOutputs(outputIndex, &dxgiOutput); 227 if (FAILED(hr)) { 228 if (hr != DXGI_ERROR_NOT_FOUND) { 229 WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIAdapter1::EnumOutputs failed", hr); 230 } 231 goto done; 232 } 233 234 hr = dxgiOutput->GetDesc(&dxgiOutputDesc); 235 if (FAILED(hr)) { 236 WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDesc failed", hr); 237 goto done; 238 } 239 240 SDL_zero(modeToMatch); 241 modeToMatch.Format = DXGI_FORMAT_B8G8R8A8_UNORM; 242 modeToMatch.Width = (dxgiOutputDesc.DesktopCoordinates.right - dxgiOutputDesc.DesktopCoordinates.left); 243 modeToMatch.Height = (dxgiOutputDesc.DesktopCoordinates.bottom - dxgiOutputDesc.DesktopCoordinates.top); 244 hr = dxgiOutput->FindClosestMatchingMode(&modeToMatch, &closestMatch, NULL); 245 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) { 246 /* DXGI_ERROR_NOT_CURRENTLY_AVAILABLE gets returned by IDXGIOutput::FindClosestMatchingMode 247 when running under the Windows Simulator, which uses Remote Desktop (formerly known as Terminal 248 Services) under the hood. According to the MSDN docs for the similar function, 249 IDXGIOutput::GetDisplayModeList, DXGI_ERROR_NOT_CURRENTLY_AVAILABLE is returned if and 250 when an app is run under a Terminal Services session, hence the assumption. 251 252 In this case, just add an SDL display mode, with approximated values. 253 */ 254 SDL_DisplayMode mode; 255 SDL_zero(mode); 256 display.name = "Windows Simulator / Terminal Services Display"; 257 mode.w = (dxgiOutputDesc.DesktopCoordinates.right - dxgiOutputDesc.DesktopCoordinates.left); 258 mode.h = (dxgiOutputDesc.DesktopCoordinates.bottom - dxgiOutputDesc.DesktopCoordinates.top); 259 mode.format = DXGI_FORMAT_B8G8R8A8_UNORM; 260 mode.refresh_rate = 0; /* Display mode is unknown, so just fill in zero, as specified by SDL's header files */ 261 display.desktop_mode = mode; 262 display.current_mode = mode; 263 if ( ! SDL_AddDisplayMode(&display, &mode)) { 264 goto done; 265 } 266 } else if (FAILED(hr)) { 267 WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::FindClosestMatchingMode failed", hr); 268 goto done; 269 } else { 270 displayName = WIN_StringToUTF8(dxgiOutputDesc.DeviceName); 271 display.name = displayName; 272 WINRT_DXGIModeToSDLDisplayMode(&closestMatch, &display.desktop_mode); 273 display.current_mode = display.desktop_mode; 274 275 hr = dxgiOutput->GetDisplayModeList(DXGI_FORMAT_B8G8R8A8_UNORM, 0, &numModes, NULL); 276 if (FAILED(hr)) { 277 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) { 278 // TODO, WinRT: make sure display mode(s) are added when using Terminal Services / Windows Simulator 279 } 280 WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDisplayModeList [get mode list size] failed", hr); 281 goto done; 282 } 283 284 dxgiModes = (DXGI_MODE_DESC *)SDL_calloc(numModes, sizeof(DXGI_MODE_DESC)); 285 if ( ! dxgiModes) { 286 SDL_OutOfMemory(); 287 goto done; 288 } 289 290 hr = dxgiOutput->GetDisplayModeList(DXGI_FORMAT_B8G8R8A8_UNORM, 0, &numModes, dxgiModes); 291 if (FAILED(hr)) { 292 WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDisplayModeList [get mode contents] failed", hr); 293 goto done; 294 } 295 296 for (UINT i = 0; i < numModes; ++i) { 297 SDL_DisplayMode sdlMode; 298 WINRT_DXGIModeToSDLDisplayMode(&dxgiModes[i], &sdlMode); 299 SDL_AddDisplayMode(&display, &sdlMode); 300 } 301 } 302 303 if (SDL_AddVideoDisplay(&display) < 0) { 304 goto done; 305 } 306 307 functionResult = 0; /* 0 for Success! */ 308done: 309 if (dxgiModes) { 310 SDL_free(dxgiModes); 311 } 312 if (dxgiOutput) { 313 dxgiOutput->Release(); 314 } 315 if (displayName) { 316 SDL_free(displayName); 317 } 318 return functionResult; 319} 320 321static int 322WINRT_AddDisplaysForAdapter (_THIS, IDXGIFactory2 * dxgiFactory2, int adapterIndex) 323{ 324 HRESULT hr; 325 IDXGIAdapter1 * dxgiAdapter1; 326 327 hr = dxgiFactory2->EnumAdapters1(adapterIndex, &dxgiAdapter1); 328 if (FAILED(hr)) { 329 if (hr != DXGI_ERROR_NOT_FOUND) { 330 WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIFactory1::EnumAdapters1() failed", hr); 331 } 332 return -1; 333 } 334 335 for (int outputIndex = 0; ; ++outputIndex) { 336 if (WINRT_AddDisplaysForOutput(_this, dxgiAdapter1, outputIndex) < 0) { 337 /* HACK: The Windows App Certification Kit 10.0 can fail, when 338 running the Store Apps' test, "Direct3D Feature Test". The 339 certification kit's error is: 340 341 "Application App was not running at the end of the test. It likely crashed or was terminated for having become unresponsive." 342 343 This was caused by SDL/WinRT's DXGI failing to report any 344 outputs. Attempts to get the 1st display-output from the 345 1st display-adapter can fail, with IDXGIAdapter::EnumOutputs 346 returning DXGI_ERROR_NOT_FOUND. This could be a bug in Windows, 347 the Windows App Certification Kit, or possibly in SDL/WinRT's 348 display detection code. Either way, try to detect when this 349 happens, and use a hackish means to create a reasonable-as-possible 350 'display mode'. -- DavidL 351 */ 352 if (adapterIndex == 0 && outputIndex == 0) { 353 SDL_VideoDisplay display; 354 SDL_DisplayMode mode; 355#if SDL_WINRT_USE_APPLICATIONVIEW 356 ApplicationView ^ appView = ApplicationView::GetForCurrentView(); 357#endif 358 CoreWindow ^ coreWin = CoreWindow::GetForCurrentThread(); 359 SDL_zero(display); 360 SDL_zero(mode); 361 display.name = "DXGI Display-detection Workaround"; 362 363 /* HACK: ApplicationView's VisibleBounds property, appeared, via testing, to 364 give a better approximation of display-size, than did CoreWindow's 365 Bounds property, insofar that ApplicationView::VisibleBounds seems like 366 it will, at least some of the time, give the full display size (during the 367 failing test), whereas CoreWindow might not. -- DavidL 368 */ 369 370#if (NTDDI_VERSION >= NTDDI_WIN10) || (SDL_WINRT_USE_APPLICATIONVIEW && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) 371 mode.w = WINRT_DIPS_TO_PHYSICAL_PIXELS(appView->VisibleBounds.Width); 372 mode.h = WINRT_DIPS_TO_PHYSICAL_PIXELS(appView->VisibleBounds.Height); 373#else 374 /* On platform(s) that do not support VisibleBounds, such as Windows 8.1, 375 fall back to CoreWindow's Bounds property. 376 */ 377 mode.w = WINRT_DIPS_TO_PHYSICAL_PIXELS(coreWin->Bounds.Width); 378 mode.h = WINRT_DIPS_TO_PHYSICAL_PIXELS(coreWin->Bounds.Height); 379#endif 380 381 mode.format = DXGI_FORMAT_B8G8R8A8_UNORM; 382 mode.refresh_rate = 0; /* Display mode is unknown, so just fill in zero, as specified by SDL's header files */ 383 display.desktop_mode = mode; 384 display.current_mode = mode; 385 if ((SDL_AddDisplayMode(&display, &mode) < 0) || 386 (SDL_AddVideoDisplay(&display) < 0)) 387 { 388 return SDL_SetError("Failed to apply DXGI Display-detection workaround"); 389 } 390 } 391 392 break; 393 } 394 } 395 396 dxgiAdapter1->Release(); 397 return 0; 398} 399 400int 401WINRT_InitModes(_THIS) 402{ 403 /* HACK: Initialize a single display, for whatever screen the app's 404 CoreApplicationView is on. 405 TODO, WinRT: Try initializing multiple displays, one for each monitor. 406 Appropriate WinRT APIs for this seem elusive, though. -- DavidL 407 */ 408 409 HRESULT hr; 410 IDXGIFactory2 * dxgiFactory2 = NULL; 411 412 hr = CreateDXGIFactory1(IID_IDXGIFactory2, (void **)&dxgiFactory2); 413 if (FAILED(hr)) { 414 WIN_SetErrorFromHRESULT(__FUNCTION__ ", CreateDXGIFactory1() failed", hr); 415 return -1; 416 } 417 418 for (int adapterIndex = 0; ; ++adapterIndex) { 419 if (WINRT_AddDisplaysForAdapter(_this, dxgiFactory2, adapterIndex) < 0) { 420 break; 421 } 422 } 423 424 return 0; 425} 426 427static int 428WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) 429{ 430 return 0; 431} 432 433void 434WINRT_VideoQuit(_THIS) 435{ 436 SDL_VideoData * driverdata = (SDL_VideoData *) _this->driverdata; 437 if (driverdata && driverdata->displayRequest) { 438 driverdata->displayRequest->Release(); 439 driverdata->displayRequest = NULL; 440 } 441 WINRT_QuitGameBar(_this); 442 WINRT_QuitMouse(_this); 443} 444 445static const Uint32 WINRT_DetectableFlags = 446 SDL_WINDOW_MAXIMIZED | 447 SDL_WINDOW_FULLSCREEN_DESKTOP | 448 SDL_WINDOW_SHOWN | 449 SDL_WINDOW_HIDDEN | 450 SDL_WINDOW_MOUSE_FOCUS; 451 452extern "C" Uint32 453WINRT_DetectWindowFlags(SDL_Window * window) 454{ 455 Uint32 latestFlags = 0; 456 SDL_WindowData * data = (SDL_WindowData *) window->driverdata; 457 bool is_fullscreen = false; 458 459#if SDL_WINRT_USE_APPLICATIONVIEW 460 if (data->appView) { 461 is_fullscreen = data->appView->IsFullScreen; 462 } 463#elif (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION == NTDDI_WIN8) 464 is_fullscreen = true; 465#endif 466 467 if (data->coreWindow.Get()) { 468 if (is_fullscreen) { 469 SDL_VideoDisplay * display = SDL_GetDisplayForWindow(window); 470 int w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width); 471 int h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height); 472 473#if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION > NTDDI_WIN8) 474 // On all WinRT platforms, except for WinPhone 8.0, rotate the 475 // window size. This is needed to properly calculate 476 // fullscreen vs. maximized. 477 const DisplayOrientations currentOrientation = WINRT_DISPLAY_PROPERTY(CurrentOrientation); 478 switch (currentOrientation) { 479#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) 480 case DisplayOrientations::Landscape: 481 case DisplayOrientations::LandscapeFlipped: 482#else 483 case DisplayOrientations::Portrait: 484 case DisplayOrientations::PortraitFlipped: 485#endif 486 { 487 int tmp = w; 488 w = h; 489 h = tmp; 490 } break; 491 } 492#endif 493 494 if (display->desktop_mode.w != w || display->desktop_mode.h != h) { 495 latestFlags |= SDL_WINDOW_MAXIMIZED; 496 } else { 497 latestFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP; 498 } 499 } 500 501 if (data->coreWindow->Visible) { 502 latestFlags |= SDL_WINDOW_SHOWN; 503 } else { 504 latestFlags |= SDL_WINDOW_HIDDEN; 505 } 506 507#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION < NTDDI_WINBLUE) 508 // data->coreWindow->PointerPosition is not supported on WinPhone 8.0 509 latestFlags |= SDL_WINDOW_MOUSE_FOCUS; 510#else 511 if (data->coreWindow->Visible && data->coreWindow->Bounds.Contains(data->coreWindow->PointerPosition)) { 512 latestFlags |= SDL_WINDOW_MOUSE_FOCUS; 513 } 514#endif 515 } 516 517 return latestFlags; 518} 519 520// TODO, WinRT: consider removing WINRT_UpdateWindowFlags, and just calling WINRT_DetectWindowFlags as-appropriate (with appropriate calls to SDL_SendWindowEvent) 521void 522WINRT_UpdateWindowFlags(SDL_Window * window, Uint32 mask) 523{ 524 mask &= WINRT_DetectableFlags; 525 if (window) { 526 Uint32 apply = WINRT_DetectWindowFlags(window); 527 if ((apply & mask) & SDL_WINDOW_FULLSCREEN) { 528 window->last_fullscreen_flags = window->flags; // seems necessary to programmatically un-fullscreen, via SDL APIs 529 } 530 window->flags = (window->flags & ~mask) | (apply & mask); 531 } 532} 533 534static bool 535WINRT_IsCoreWindowActive(CoreWindow ^ coreWindow) 536{ 537 /* WinRT does not appear to offer API(s) to determine window-activation state, 538 at least not that I am aware of in Win8 - Win10. As such, SDL tracks this 539 itself, via window-activation events. 540 541 If there *is* an API to track this, it should probably get used instead 542 of the following hack (that uses "SDLHelperWindowActivationState"). 543 -- DavidL. 544 */ 545 if (coreWindow->CustomProperties->HasKey("SDLHelperWindowActivationState")) { 546 CoreWindowActivationState activationState = \ 547 safe_cast<CoreWindowActivationState>(coreWindow->CustomProperties->Lookup("SDLHelperWindowActivationState")); 548 return (activationState != CoreWindowActivationState::Deactivated); 549 } 550 551 /* Assume that non-SDL tracked windows are active, although this should 552 probably be avoided, if possible. 553 554 This might not even be possible, in normal SDL use, at least as of 555 this writing (Dec 22, 2015; via latest hg.libsdl.org/SDL clone) -- DavidL 556 */ 557 return true; 558} 559 560int 561WINRT_CreateWindow(_THIS, SDL_Window * window) 562{ 563 // Make sure that only one window gets created, at least until multimonitor 564 // support is added. 565 if (WINRT_GlobalSDLWindow != NULL) { 566 SDL_SetError("WinRT only supports one window"); 567 return -1; 568 } 569 570 SDL_WindowData *data = new SDL_WindowData; /* use 'new' here as SDL_WindowData may use WinRT/C++ types */ 571 if (!data) { 572 SDL_OutOfMemory(); 573 return -1; 574 } 575 window->driverdata = data; 576 data->sdlWindow = window; 577 578 /* To note, when XAML support is enabled, access to the CoreWindow will not 579 be possible, at least not via the SDL/XAML thread. Attempts to access it 580 from there will throw exceptions. As such, the SDL_WindowData's 581 'coreWindow' field will only be set (to a non-null value) if XAML isn't 582 enabled. 583 */ 584 if (!WINRT_XAMLWasEnabled) { 585 data->coreWindow = CoreWindow::GetForCurrentThread(); 586#if SDL_WINRT_USE_APPLICATIONVIEW 587 data->appView = ApplicationView::GetForCurrentView(); 588#endif 589 } 590 591 /* Make note of the requested window flags, before they start getting changed. */ 592 const Uint32 requestedFlags = window->flags; 593 594#if SDL_VIDEO_OPENGL_EGL 595 /* Setup the EGL surface, but only if OpenGL ES 2 was requested. */ 596 if (!(window->flags & SDL_WINDOW_OPENGL)) { 597 /* OpenGL ES 2 wasn't requested. Don't set up an EGL surface. */ 598 data->egl_surface = EGL_NO_SURFACE; 599 } else { 600 /* OpenGL ES 2 was reuqested. Set up an EGL surface. */ 601 SDL_VideoData * video_data = (SDL_VideoData *)_this->driverdata; 602 603 /* Call SDL_EGL_ChooseConfig and eglCreateWindowSurface directly, 604 * rather than via SDL_EGL_CreateSurface, as older versions of 605 * ANGLE/WinRT may require that a C++ object, ComPtr<IUnknown>, 606 * be passed into eglCreateWindowSurface. 607 */ 608 if (SDL_EGL_ChooseConfig(_this) != 0) { 609 char buf[512]; 610 SDL_snprintf(buf, sizeof(buf), "SDL_EGL_ChooseConfig failed: %s", SDL_GetError()); 611 return SDL_SetError("%s", buf); 612 } 613 614 if (video_data->winrtEglWindow) { /* ... is the 'old' version of ANGLE/WinRT being used? */ 615 /* Attempt to create a window surface using older versions of 616 * ANGLE/WinRT: 617 */ 618 Microsoft::WRL::ComPtr<IUnknown> cpp_winrtEglWindow = video_data->winrtEglWindow; 619 data->egl_surface = ((eglCreateWindowSurface_Old_Function)_this->egl_data->eglCreateWindowSurface)( 620 _this->egl_data->egl_display, 621 _this->egl_data->egl_config, 622 cpp_winrtEglWindow, NULL); 623 if (data->egl_surface == NULL) { 624 return SDL_EGL_SetError("unable to create EGL native-window surface", "eglCreateWindowSurface"); 625 } 626 } else if (data->coreWindow.Get() != nullptr) { 627 /* Attempt to create a window surface using newer versions of 628 * ANGLE/WinRT: 629 */ 630 IInspectable * coreWindowAsIInspectable = reinterpret_cast<IInspectable *>(data->coreWindow.Get()); 631 data->egl_surface = _this->egl_data->eglCreateWindowSurface( 632 _this->egl_data->egl_display, 633 _this->egl_data->egl_config, 634 coreWindowAsIInspectable, 635 NULL); 636 if (data->egl_surface == NULL) { 637 return SDL_EGL_SetError("unable to create EGL native-window surface", "eglCreateWindowSurface"); 638 } 639 } else { 640 return SDL_SetError("No supported means to create an EGL window surface are available"); 641 } 642 } 643#endif 644 645 /* Determine as many flags dynamically, as possible. */ 646 window->flags = 647 SDL_WINDOW_BORDERLESS | 648 SDL_WINDOW_RESIZABLE; 649 650#if SDL_VIDEO_OPENGL_EGL 651 if (data->egl_surface) { 652 window->flags |= SDL_WINDOW_OPENGL; 653 } 654#endif 655 656 if (WINRT_XAMLWasEnabled) { 657 /* TODO, WinRT: set SDL_Window size, maybe position too, from XAML control */ 658 window->x = 0; 659 window->y = 0; 660 window->flags |= SDL_WINDOW_SHOWN; 661 SDL_SetMouseFocus(NULL); // TODO: detect this 662 SDL_SetKeyboardFocus(NULL); // TODO: detect this 663 } else { 664 /* WinRT 8.x apps seem to live in an environment where the OS controls the 665 app's window size, with some apps being fullscreen, depending on 666 user choice of various things. For now, just adapt the SDL_Window to 667 whatever Windows set-up as the native-window's geometry. 668 */ 669 window->x = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Left); 670 window->y = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Top); 671#if NTDDI_VERSION < NTDDI_WIN10 672 /* On WinRT 8.x / pre-Win10, just use the size we were given. */ 673 window->w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width); 674 window->h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height); 675#else 676 /* On Windows 10, we occasionally get control over window size. For windowed 677 mode apps, try this. 678 */ 679 bool didSetSize = false; 680 if (!(requestedFlags & SDL_WINDOW_FULLSCREEN)) { 681 const Windows::Foundation::Size size(WINRT_PHYSICAL_PIXELS_TO_DIPS(window->w), 682 WINRT_PHYSICAL_PIXELS_TO_DIPS(window->h)); 683 didSetSize = data->appView->TryResizeView(size); 684 } 685 if (!didSetSize) { 686 /* We either weren't able to set the window size, or a request for 687 fullscreen was made. Get window-size info from the OS. 688 */ 689 window->w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width); 690 window->h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height); 691 } 692#endif 693 694 WINRT_UpdateWindowFlags( 695 window, 696 0xffffffff /* Update any window flag(s) that WINRT_UpdateWindow can handle */ 697 ); 698 699 /* Try detecting if the window is active */ 700 bool isWindowActive = WINRT_IsCoreWindowActive(data->coreWindow.Get()); 701 if (isWindowActive) { 702 SDL_SetKeyboardFocus(window); 703 } 704 } 705 706 /* Make sure the WinRT app's IFramworkView can post events on 707 behalf of SDL: 708 */ 709 WINRT_GlobalSDLWindow = window; 710 711 /* All done! */ 712 return 0; 713} 714 715void 716WINRT_SetWindowSize(_THIS, SDL_Window * window) 717{ 718#if NTDDI_VERSION >= NTDDI_WIN10 719 SDL_WindowData * data = (SDL_WindowData *)window->driverdata; 720 const Windows::Foundation::Size size(WINRT_PHYSICAL_PIXELS_TO_DIPS(window->w), 721 WINRT_PHYSICAL_PIXELS_TO_DIPS(window->h)); 722 data->appView->TryResizeView(size); // TODO, WinRT: return failure (to caller?) from TryResizeView() 723#endif 724} 725 726void 727WINRT_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen) 728{ 729#if NTDDI_VERSION >= NTDDI_WIN10 730 SDL_WindowData * data = (SDL_WindowData *)window->driverdata; 731 bool isWindowActive = WINRT_IsCoreWindowActive(data->coreWindow.Get()); 732 if (isWindowActive) { 733 if (fullscreen) { 734 if (!data->appView->IsFullScreenMode) { 735 data->appView->TryEnterFullScreenMode(); // TODO, WinRT: return failure (to caller?) from TryEnterFullScreenMode() 736 } 737 } else { 738 if (data->appView->IsFullScreenMode) { 739 data->appView->ExitFullScreenMode(); 740 } 741 } 742 } 743#endif 744} 745 746 747void 748WINRT_DestroyWindow(_THIS, SDL_Window * window) 749{ 750 SDL_WindowData * data = (SDL_WindowData *) window->driverdata; 751 752 if (WINRT_GlobalSDLWindow == window) { 753 WINRT_GlobalSDLWindow = NULL; 754 } 755 756 if (data) { 757 // Delete the internal window data: 758 delete data; 759 data = NULL; 760 window->driverdata = NULL; 761 } 762} 763 764SDL_bool 765WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) 766{ 767 SDL_WindowData * data = (SDL_WindowData *) window->driverdata; 768 769 if (info->version.major <= SDL_MAJOR_VERSION) { 770 info->subsystem = SDL_SYSWM_WINRT; 771 info->info.winrt.window = reinterpret_cast<IInspectable *>(data->coreWindow.Get()); 772 return SDL_TRUE; 773 } else { 774 SDL_SetError("Application not compiled with SDL %d.%d", 775 SDL_MAJOR_VERSION, SDL_MINOR_VERSION); 776 return SDL_FALSE; 777 } 778 return SDL_FALSE; 779} 780 781static ABI::Windows::System::Display::IDisplayRequest * 782WINRT_CreateDisplayRequest(_THIS) 783{ 784 /* Setup a WinRT DisplayRequest object, usable for enabling/disabling screensaver requests */ 785 wchar_t *wClassName = L"Windows.System.Display.DisplayRequest"; 786 HSTRING hClassName; 787 IActivationFactory *pActivationFactory = NULL; 788 IInspectable * pDisplayRequestRaw = nullptr; 789 ABI::Windows::System::Display::IDisplayRequest * pDisplayRequest = nullptr; 790 HRESULT hr; 791 792 hr = ::WindowsCreateString(wClassName, (UINT32)wcslen(wClassName), &hClassName); 793 if (FAILED(hr)) { 794 goto done; 795 } 796 797 hr = Windows::Foundation::GetActivationFactory(hClassName, &pActivationFactory); 798 if (FAILED(hr)) { 799 goto done; 800 } 801 802 hr = pActivationFactory->ActivateInstance(&pDisplayRequestRaw); 803 if (FAILED(hr)) { 804 goto done; 805 } 806 807 hr = pDisplayRequestRaw->QueryInterface(IID_IDisplayRequest, (void **) &pDisplayRequest); 808 if (FAILED(hr)) { 809 goto done; 810 } 811 812done: 813 if (pDisplayRequestRaw) { 814 pDisplayRequestRaw->Release(); 815 } 816 if (pActivationFactory) { 817 pActivationFactory->Release(); 818 } 819 if (hClassName) { 820 ::WindowsDeleteString(hClassName); 821 } 822 823 return pDisplayRequest; 824} 825 826void 827WINRT_SuspendScreenSaver(_THIS) 828{ 829 SDL_VideoData *driverdata = (SDL_VideoData *)_this->driverdata; 830 if (driverdata && driverdata->displayRequest) { 831 ABI::Windows::System::Display::IDisplayRequest * displayRequest = (ABI::Windows::System::Display::IDisplayRequest *) driverdata->displayRequest; 832 if (_this->suspend_screensaver) { 833 displayRequest->RequestActive(); 834 } else { 835 displayRequest->RequestRelease(); 836 } 837 } 838} 839 840#endif /* SDL_VIDEO_DRIVER_WINRT */ 841 842/* vi: set ts=4 sw=4 expandtab: */ 843
[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.