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