1 /// Translated from C to D 2 module glfw3.win32_monitor; 3 4 extern(C): @nogc: nothrow: __gshared: 5 //======================================================================== 6 // GLFW 3.3 Win32 - www.glfw.org 7 //------------------------------------------------------------------------ 8 // Copyright (c) 2002-2006 Marcus Geelnard 9 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org> 10 // 11 // This software is provided 'as-is', without any express or implied 12 // warranty. In no event will the authors be held liable for any damages 13 // arising from the use of this software. 14 // 15 // Permission is granted to anyone to use this software for any purpose, 16 // including commercial applications, and to alter it and redistribute it 17 // freely, subject to the following restrictions: 18 // 19 // 1. The origin of this software must not be misrepresented; you must not 20 // claim that you wrote the original software. If you use this software 21 // in a product, an acknowledgment in the product documentation would 22 // be appreciated but is not required. 23 // 24 // 2. Altered source versions must be plainly marked as such, and must not 25 // be misrepresented as being the original software. 26 // 27 // 3. This notice may not be removed or altered from any source 28 // distribution. 29 // 30 //======================================================================== 31 // Please use C89 style variable declarations in this file because VS 2010 32 //======================================================================== 33 34 import glfw3.internal; 35 36 import core.stdc.stdlib; 37 import core.stdc.string; 38 import core.stdc.limits; 39 import core.stdc.wchar_; 40 41 package: 42 43 // Callback for EnumDisplayMonitors in createMonitor 44 // 45 extern(Windows) private BOOL monitorCallback(HMONITOR handle, HDC dc, RECT* rect, LPARAM data) { 46 MONITORINFOEXW mi; 47 memset(&mi, 0, typeof(mi).sizeof); 48 mi.cbSize = typeof(mi).sizeof; 49 50 if (GetMonitorInfoW(handle, cast(MONITORINFO*) &mi)) 51 { 52 _GLFWmonitor* monitor = cast(_GLFWmonitor*) data; 53 if (wcscmp(mi.szDevice.ptr, monitor.win32.adapterName.ptr) == 0) 54 monitor.win32.handle = handle; 55 } 56 57 return TRUE; 58 } 59 60 // Create monitor from an adapter and (optionally) a display 61 // 62 private extern(D) _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter, DISPLAY_DEVICEW* display) { 63 _GLFWmonitor* monitor; 64 int widthMM;int heightMM; 65 char* name; 66 HDC dc; 67 DEVMODEW dm; 68 RECT rect; 69 70 if (display) 71 name = _glfwCreateUTF8FromWideStringWin32(display.DeviceString.ptr); 72 else 73 name = _glfwCreateUTF8FromWideStringWin32(adapter.DeviceString.ptr); 74 if (!name) 75 return null; 76 77 memset(&dm, 0, typeof(dm).sizeof); 78 dm.dmSize = typeof(dm).sizeof; 79 EnumDisplaySettingsW(adapter.DeviceName.ptr, ENUM_CURRENT_SETTINGS, &dm); 80 81 dc = CreateDCW("DISPLAY"w.ptr, adapter.DeviceName.ptr, null, null); 82 83 if (IsWindows8Point1OrGreater()) 84 { 85 widthMM = GetDeviceCaps(dc, HORZSIZE); 86 heightMM = GetDeviceCaps(dc, VERTSIZE); 87 } 88 else 89 { 90 widthMM = cast(int) (dm.dmPelsWidth * 25.4f / GetDeviceCaps(dc, LOGPIXELSX)); 91 heightMM = cast(int) (dm.dmPelsHeight * 25.4f / GetDeviceCaps(dc, LOGPIXELSY)); 92 } 93 94 DeleteDC(dc); 95 96 monitor = _glfwAllocMonitor(name, widthMM, heightMM); 97 free(name); 98 99 if (adapter.StateFlags & DISPLAY_DEVICE_MODESPRUNED) 100 monitor.win32.modesPruned = GLFW_TRUE; 101 102 wcscpy(monitor.win32.adapterName.ptr, adapter.DeviceName.ptr); 103 WideCharToMultiByte(CP_UTF8, 0, 104 adapter.DeviceName.ptr, -1, 105 monitor.win32.publicAdapterName.ptr, 106 typeof(monitor.win32.publicAdapterName).sizeof, 107 null, null); 108 109 if (display) 110 { 111 wcscpy(monitor.win32.displayName.ptr, display.DeviceName.ptr); 112 WideCharToMultiByte(CP_UTF8, 0, 113 display.DeviceName.ptr, -1, 114 monitor.win32.publicDisplayName.ptr, 115 typeof(monitor.win32.publicDisplayName).sizeof, 116 null, null); 117 } 118 119 rect.left = dm.dmPosition.x; 120 rect.top = dm.dmPosition.y; 121 rect.right = dm.dmPosition.x + dm.dmPelsWidth; 122 rect.bottom = dm.dmPosition.y + dm.dmPelsHeight; 123 124 EnumDisplayMonitors(null, &rect, &monitorCallback, cast(LPARAM) monitor); 125 return monitor; 126 } 127 128 129 ////////////////////////////////////////////////////////////////////////// 130 ////// GLFW internal API ////// 131 ////////////////////////////////////////////////////////////////////////// 132 133 // Poll for changes in the set of connected monitors 134 // 135 void _glfwPollMonitorsWin32() { 136 int i;int disconnectedCount; 137 _GLFWmonitor** disconnected = null; 138 DWORD adapterIndex;DWORD displayIndex; 139 DISPLAY_DEVICEW adapter;DISPLAY_DEVICEW display; 140 _GLFWmonitor* monitor; 141 142 disconnectedCount = _glfw.monitorCount; 143 if (disconnectedCount) 144 { 145 disconnected = cast(_GLFWmonitor**) calloc(_glfw.monitorCount, (_GLFWmonitor*).sizeof); 146 memcpy(disconnected, 147 _glfw.monitors, 148 _glfw.monitorCount * (_GLFWmonitor*).sizeof); 149 } 150 151 for (adapterIndex = 0; ; adapterIndex++) 152 { 153 int type = _GLFW_INSERT_LAST; 154 155 memset(&adapter, 0, typeof(adapter).sizeof); 156 adapter.cb = typeof(adapter).sizeof; 157 158 if (!EnumDisplayDevicesW(null, adapterIndex, &adapter, 0)) 159 break; 160 161 if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE)) 162 continue; 163 164 if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) 165 type = _GLFW_INSERT_FIRST; 166 167 for (displayIndex = 0; ; displayIndex++) 168 { 169 memset(&display, 0, typeof(display).sizeof); 170 display.cb = typeof(display).sizeof; 171 172 if (!EnumDisplayDevicesW(adapter.DeviceName.ptr, displayIndex, &display, 0)) 173 break; 174 175 if (!(display.StateFlags & DISPLAY_DEVICE_ACTIVE)) 176 continue; 177 178 for (i = 0; i < disconnectedCount; i++) 179 { 180 if (disconnected[i] && 181 wcscmp(disconnected[i].win32.displayName.ptr, 182 display.DeviceName.ptr) == 0) 183 { 184 disconnected[i] = null; 185 break; 186 } 187 } 188 189 if (i < disconnectedCount) 190 continue; 191 192 monitor = createMonitor(&adapter, &display); 193 if (!monitor) 194 { 195 free(disconnected); 196 return; 197 } 198 199 _glfwInputMonitor(monitor, GLFW_CONNECTED, type); 200 201 type = _GLFW_INSERT_LAST; 202 } 203 204 // HACK: If an active adapter does not have any display devices 205 // (as sometimes happens), add it directly as a monitor 206 if (displayIndex == 0) 207 { 208 for (i = 0; i < disconnectedCount; i++) 209 { 210 if (disconnected[i] && 211 wcscmp(disconnected[i].win32.adapterName.ptr, 212 adapter.DeviceName.ptr) == 0) 213 { 214 disconnected[i] = null; 215 break; 216 } 217 } 218 219 if (i < disconnectedCount) 220 continue; 221 222 monitor = createMonitor(&adapter, null); 223 if (!monitor) 224 { 225 free(disconnected); 226 return; 227 } 228 229 _glfwInputMonitor(monitor, GLFW_CONNECTED, type); 230 } 231 } 232 233 for (i = 0; i < disconnectedCount; i++) 234 { 235 if (disconnected[i]) 236 _glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0); 237 } 238 239 free(disconnected); 240 } 241 242 // Change the current video mode 243 // 244 void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const(GLFWvidmode)* desired) { 245 GLFWvidmode current; 246 const(GLFWvidmode)* best; 247 DEVMODEW dm; 248 LONG result; 249 250 best = _glfwChooseVideoMode(monitor, desired); 251 _glfwPlatformGetVideoMode(monitor, ¤t); 252 if (_glfwCompareVideoModes(¤t, best) == 0) 253 return; 254 255 memset(&dm, 0, typeof(dm).sizeof); 256 dm.dmSize = typeof(dm).sizeof; 257 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | 258 DM_DISPLAYFREQUENCY; 259 dm.dmPelsWidth = best.width; 260 dm.dmPelsHeight = best.height; 261 dm.dmBitsPerPel = best.redBits + best.greenBits + best.blueBits; 262 dm.dmDisplayFrequency = best.refreshRate; 263 264 if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24) 265 dm.dmBitsPerPel = 32; 266 267 result = ChangeDisplaySettingsExW(monitor.win32.adapterName.ptr, 268 &dm, 269 null, 270 CDS_FULLSCREEN, 271 null); 272 if (result == DISP_CHANGE_SUCCESSFUL) 273 monitor.win32.modeChanged = GLFW_TRUE; 274 else 275 { 276 const(char)* description = "Unknown error"; 277 278 if (result == DISP_CHANGE_BADDUALVIEW) 279 description = "The system uses DualView"; 280 else if (result == DISP_CHANGE_BADFLAGS) 281 description = "Invalid flags"; 282 else if (result == DISP_CHANGE_BADMODE) 283 description = "Graphics mode not supported"; 284 else if (result == DISP_CHANGE_BADPARAM) 285 description = "Invalid parameter"; 286 else if (result == DISP_CHANGE_FAILED) 287 description = "Graphics mode failed"; 288 else if (result == DISP_CHANGE_NOTUPDATED) 289 description = "Failed to write to registry"; 290 else if (result == DISP_CHANGE_RESTART) 291 description = "Computer restart required"; 292 293 _glfwInputError(GLFW_PLATFORM_ERROR, 294 "Win32: Failed to set video mode: %s", 295 description); 296 } 297 } 298 299 // Restore the previously saved (original) video mode 300 // 301 void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor) { 302 if (monitor.win32.modeChanged) 303 { 304 ChangeDisplaySettingsExW(monitor.win32.adapterName.ptr, 305 null, null, CDS_FULLSCREEN, null); 306 monitor.win32.modeChanged = GLFW_FALSE; 307 } 308 } 309 310 void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* yscale) { 311 UINT xdpi;UINT ydpi; 312 313 if (IsWindows8Point1OrGreater()) 314 mixin(GetDpiForMonitor)(handle, MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, &xdpi, &ydpi); 315 else 316 { 317 HDC dc = GetDC(null); 318 xdpi = GetDeviceCaps(dc, LOGPIXELSX); 319 ydpi = GetDeviceCaps(dc, LOGPIXELSY); 320 ReleaseDC(null, dc); 321 } 322 323 if (xscale) 324 *xscale = xdpi / cast(float) USER_DEFAULT_SCREEN_DPI; 325 if (yscale) 326 *yscale = ydpi / cast(float) USER_DEFAULT_SCREEN_DPI; 327 } 328 329 330 ////////////////////////////////////////////////////////////////////////// 331 ////// GLFW platform API ////// 332 ////////////////////////////////////////////////////////////////////////// 333 334 void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor) { 335 } 336 337 void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { 338 DEVMODEW dm; 339 memset(&dm, 0, typeof(dm).sizeof); 340 dm.dmSize = typeof(dm).sizeof; 341 342 EnumDisplaySettingsExW(monitor.win32.adapterName.ptr, 343 ENUM_CURRENT_SETTINGS, 344 &dm, 345 EDS_ROTATEDMODE); 346 347 if (xpos) 348 *xpos = dm.dmPosition.x; 349 if (ypos) 350 *ypos = dm.dmPosition.y; 351 } 352 353 void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor, float* xscale, float* yscale) { 354 _glfwGetMonitorContentScaleWin32(monitor.win32.handle, xscale, yscale); 355 } 356 357 void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height) { 358 MONITORINFO mi = MONITORINFO(MONITORINFO.sizeof); 359 GetMonitorInfo(monitor.win32.handle, &mi); 360 361 if (xpos) 362 *xpos = mi.rcWork.left; 363 if (ypos) 364 *ypos = mi.rcWork.top; 365 if (width) 366 *width = mi.rcWork.right - mi.rcWork.left; 367 if (height) 368 *height = mi.rcWork.bottom - mi.rcWork.top; 369 } 370 371 GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) { 372 int modeIndex = 0;int size = 0; 373 GLFWvidmode* result = null; 374 375 *count = 0; 376 377 for (;;) 378 { 379 int i; 380 GLFWvidmode mode; 381 DEVMODEW dm; 382 383 memset(&dm, 0, typeof(dm).sizeof); 384 dm.dmSize = typeof(dm).sizeof; 385 386 if (!EnumDisplaySettingsW(monitor.win32.adapterName.ptr, modeIndex, &dm)) 387 break; 388 389 modeIndex++; 390 391 // Skip modes with less than 15 BPP 392 if (dm.dmBitsPerPel < 15) 393 continue; 394 395 mode.width = dm.dmPelsWidth; 396 mode.height = dm.dmPelsHeight; 397 mode.refreshRate = dm.dmDisplayFrequency; 398 _glfwSplitBPP(dm.dmBitsPerPel, 399 &mode.redBits, 400 &mode.greenBits, 401 &mode.blueBits); 402 403 for (i = 0; i < *count; i++) 404 { 405 if (_glfwCompareVideoModes(result + i, &mode) == 0) 406 break; 407 } 408 409 // Skip duplicate modes 410 if (i < *count) 411 continue; 412 413 if (monitor.win32.modesPruned) 414 { 415 // Skip modes not supported by the connected displays 416 if (ChangeDisplaySettingsExW(monitor.win32.adapterName.ptr, 417 &dm, 418 null, 419 CDS_TEST, 420 null) != DISP_CHANGE_SUCCESSFUL) 421 { 422 continue; 423 } 424 } 425 426 if (*count == size) 427 { 428 size += 128; 429 result = cast(GLFWvidmode*) realloc(result, size * GLFWvidmode.sizeof); 430 } 431 432 (*count)++; 433 result[*count - 1] = mode; 434 } 435 436 if (!*count) 437 { 438 // HACK: Report the current mode if no valid modes were found 439 result = cast(GLFWvidmode*) calloc(1, GLFWvidmode.sizeof); 440 _glfwPlatformGetVideoMode(monitor, result); 441 *count = 1; 442 } 443 444 return result; 445 } 446 447 void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { 448 DEVMODEW dm; 449 memset(&dm, 0, typeof(dm).sizeof); 450 dm.dmSize = typeof(dm).sizeof; 451 452 EnumDisplaySettingsW(monitor.win32.adapterName.ptr, ENUM_CURRENT_SETTINGS, &dm); 453 454 mode.width = dm.dmPelsWidth; 455 mode.height = dm.dmPelsHeight; 456 mode.refreshRate = dm.dmDisplayFrequency; 457 _glfwSplitBPP(dm.dmBitsPerPel, 458 &mode.redBits, 459 &mode.greenBits, 460 &mode.blueBits); 461 } 462 463 GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) { 464 HDC dc; 465 WORD[256][3] values; 466 467 dc = CreateDCW("DISPLAY"w.ptr, monitor.win32.adapterName.ptr, null, null); 468 GetDeviceGammaRamp(dc, values.ptr); 469 DeleteDC(dc); 470 471 _glfwAllocGammaArrays(ramp, 256); 472 473 memcpy(ramp.red, values[0].ptr, typeof(values[0]).sizeof); 474 memcpy(ramp.green, values[1].ptr, typeof(values[1]).sizeof); 475 memcpy(ramp.blue, values[2].ptr, typeof(values[2]).sizeof); 476 477 return GLFW_TRUE; 478 } 479 480 void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const(GLFWgammaramp)* ramp) { 481 HDC dc; 482 WORD[256][3] values; 483 484 if (ramp.size != 256) 485 { 486 _glfwInputError(GLFW_PLATFORM_ERROR, 487 "Win32: Gamma ramp size must be 256"); 488 return; 489 } 490 491 memcpy(values[0].ptr, ramp.red, typeof(values[0]).sizeof); 492 memcpy(values[1].ptr, ramp.green, typeof(values[1]).sizeof); 493 memcpy(values[2].ptr, ramp.blue, typeof(values[2]).sizeof); 494 495 dc = CreateDCW("DISPLAY"w.ptr, monitor.win32.adapterName.ptr, null, null); 496 SetDeviceGammaRamp(dc, values.ptr); 497 DeleteDC(dc); 498 } 499 500 501 ////////////////////////////////////////////////////////////////////////// 502 ////// GLFW native API ////// 503 ////////////////////////////////////////////////////////////////////////// 504 505 const(char)* glfwGetWin32Adapter(GLFWmonitor* handle) { 506 _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; 507 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 508 return monitor.win32.publicAdapterName.ptr; 509 } 510 511 const(char)* glfwGetWin32Monitor(GLFWmonitor* handle) { 512 _GLFWmonitor* monitor = cast(_GLFWmonitor*) handle; 513 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 514 return monitor.win32.publicDisplayName.ptr; 515 }