Atlas - SDL_windowsmodes.c
Home / ext / SDL2 / src / video / windows Lines: 2 | Size: 12519 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 "SDL_windowsvideo.h" 26#include "../../../include/SDL_assert.h" 27#include "../../../include/SDL_log.h" 28 29/* Windows CE compatibility */ 30#ifndef CDS_FULLSCREEN 31#define CDS_FULLSCREEN 0 32#endif 33 34/* #define DEBUG_MODES */ 35 36static void 37WIN_UpdateDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode) 38{ 39 SDL_DisplayModeData *data = (SDL_DisplayModeData *) mode->driverdata; 40 HDC hdc; 41 42 data->DeviceMode.dmFields = 43 (DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | 44 DM_DISPLAYFLAGS); 45 46 if (index == ENUM_CURRENT_SETTINGS 47 && (hdc = CreateDC(deviceName, NULL, NULL, NULL)) != NULL) { 48 char bmi_data[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)]; 49 LPBITMAPINFO bmi; 50 HBITMAP hbm; 51 int logical_width = GetDeviceCaps( hdc, HORZRES ); 52 int logical_height = GetDeviceCaps( hdc, VERTRES ); 53 54 mode->w = logical_width; 55 mode->h = logical_height; 56 57 SDL_zero(bmi_data); 58 bmi = (LPBITMAPINFO) bmi_data; 59 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 60 61 hbm = CreateCompatibleBitmap(hdc, 1, 1); 62 GetDIBits(hdc, hbm, 0, 1, NULL, bmi, DIB_RGB_COLORS); 63 GetDIBits(hdc, hbm, 0, 1, NULL, bmi, DIB_RGB_COLORS); 64 DeleteObject(hbm); 65 DeleteDC(hdc); 66 if (bmi->bmiHeader.biCompression == BI_BITFIELDS) { 67 switch (*(Uint32 *) bmi->bmiColors) { 68 case 0x00FF0000: 69 mode->format = SDL_PIXELFORMAT_RGB888; 70 break; 71 case 0x000000FF: 72 mode->format = SDL_PIXELFORMAT_BGR888; 73 break; 74 case 0xF800: 75 mode->format = SDL_PIXELFORMAT_RGB565; 76 break; 77 case 0x7C00: 78 mode->format = SDL_PIXELFORMAT_RGB555; 79 break; 80 } 81 } else if (bmi->bmiHeader.biBitCount == 8) { 82 mode->format = SDL_PIXELFORMAT_INDEX8; 83 } else if (bmi->bmiHeader.biBitCount == 4) { 84 mode->format = SDL_PIXELFORMAT_INDEX4LSB; 85 } 86 } else if (mode->format == SDL_PIXELFORMAT_UNKNOWN) { 87 /* FIXME: Can we tell what this will be? */ 88 if ((data->DeviceMode.dmFields & DM_BITSPERPEL) == DM_BITSPERPEL) { 89 switch (data->DeviceMode.dmBitsPerPel) { 90 case 32: 91 mode->format = SDL_PIXELFORMAT_RGB888; 92 break; 93 case 24: 94 mode->format = SDL_PIXELFORMAT_RGB24; 95 break; 96 case 16: 97 mode->format = SDL_PIXELFORMAT_RGB565; 98 break; 99 case 15: 100 mode->format = SDL_PIXELFORMAT_RGB555; 101 break; 102 case 8: 103 mode->format = SDL_PIXELFORMAT_INDEX8; 104 break; 105 case 4: 106 mode->format = SDL_PIXELFORMAT_INDEX4LSB; 107 break; 108 } 109 } 110 } 111} 112 113static SDL_bool 114WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode) 115{ 116 SDL_DisplayModeData *data; 117 DEVMODE devmode; 118 119 devmode.dmSize = sizeof(devmode); 120 devmode.dmDriverExtra = 0; 121 if (!EnumDisplaySettings(deviceName, index, &devmode)) { 122 return SDL_FALSE; 123 } 124 125 data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data)); 126 if (!data) { 127 return SDL_FALSE; 128 } 129 130 mode->driverdata = data; 131 data->DeviceMode = devmode; 132 133 mode->format = SDL_PIXELFORMAT_UNKNOWN; 134 mode->w = data->DeviceMode.dmPelsWidth; 135 mode->h = data->DeviceMode.dmPelsHeight; 136 mode->refresh_rate = data->DeviceMode.dmDisplayFrequency; 137 138 /* Fill in the mode information */ 139 WIN_UpdateDisplayMode(_this, deviceName, index, mode); 140 return SDL_TRUE; 141} 142 143static SDL_bool 144WIN_AddDisplay(_THIS, HMONITOR hMonitor, const MONITORINFOEX *info) 145{ 146 SDL_VideoDisplay display; 147 SDL_DisplayData *displaydata; 148 SDL_DisplayMode mode; 149 DISPLAY_DEVICE device; 150 151#ifdef DEBUG_MODES 152 SDL_Log("Display: %s\n", WIN_StringToUTF8(info->szDevice)); 153#endif 154 155 if (!WIN_GetDisplayMode(_this, info->szDevice, ENUM_CURRENT_SETTINGS, &mode)) { 156 return SDL_FALSE; 157 } 158 159 displaydata = (SDL_DisplayData *) SDL_malloc(sizeof(*displaydata)); 160 if (!displaydata) { 161 return SDL_FALSE; 162 } 163 SDL_memcpy(displaydata->DeviceName, info->szDevice, 164 sizeof(displaydata->DeviceName)); 165 displaydata->MonitorHandle = hMonitor; 166 167 SDL_zero(display); 168 device.cb = sizeof(device); 169 if (EnumDisplayDevices(info->szDevice, 0, &device, 0)) { 170 display.name = WIN_StringToUTF8(device.DeviceString); 171 } 172 display.desktop_mode = mode; 173 display.current_mode = mode; 174 display.driverdata = displaydata; 175 SDL_AddVideoDisplay(&display); 176 SDL_free(display.name); 177 return SDL_TRUE; 178} 179 180typedef struct _WIN_AddDisplaysData { 181 SDL_VideoDevice *video_device; 182 SDL_bool want_primary; 183} WIN_AddDisplaysData; 184 185static BOOL CALLBACK 186WIN_AddDisplaysCallback(HMONITOR hMonitor, 187 HDC hdcMonitor, 188 LPRECT lprcMonitor, 189 LPARAM dwData) 190{ 191 WIN_AddDisplaysData *data = (WIN_AddDisplaysData*)dwData; 192 MONITORINFOEX info; 193 194 SDL_zero(info); 195 info.cbSize = sizeof(info); 196 197 if (GetMonitorInfo(hMonitor, (LPMONITORINFO)&info) != 0) { 198 const SDL_bool is_primary = ((info.dwFlags & MONITORINFOF_PRIMARY) == MONITORINFOF_PRIMARY); 199 200 if (is_primary == data->want_primary) { 201 WIN_AddDisplay(data->video_device, hMonitor, &info); 202 } 203 } 204 205 // continue enumeration 206 return TRUE; 207} 208 209static void 210WIN_AddDisplays(_THIS) 211{ 212 WIN_AddDisplaysData callback_data; 213 callback_data.video_device = _this; 214 215 callback_data.want_primary = SDL_TRUE; 216 EnumDisplayMonitors(NULL, NULL, WIN_AddDisplaysCallback, (LPARAM)&callback_data); 217 218 callback_data.want_primary = SDL_FALSE; 219 EnumDisplayMonitors(NULL, NULL, WIN_AddDisplaysCallback, (LPARAM)&callback_data); 220} 221 222int 223WIN_InitModes(_THIS) 224{ 225 WIN_AddDisplays(_this); 226 227 if (_this->num_displays == 0) { 228 return SDL_SetError("No displays available"); 229 } 230 return 0; 231} 232 233int 234WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect) 235{ 236 const SDL_DisplayData *data = (const SDL_DisplayData *)display->driverdata; 237 MONITORINFO minfo; 238 BOOL rc; 239 240 SDL_zero(minfo); 241 minfo.cbSize = sizeof(MONITORINFO); 242 rc = GetMonitorInfo(data->MonitorHandle, &minfo); 243 244 if (!rc) { 245 return SDL_SetError("Couldn't find monitor data"); 246 } 247 248 rect->x = minfo.rcMonitor.left; 249 rect->y = minfo.rcMonitor.top; 250 rect->w = minfo.rcMonitor.right - minfo.rcMonitor.left; 251 rect->h = minfo.rcMonitor.bottom - minfo.rcMonitor.top; 252 253 return 0; 254} 255 256int 257WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi_out, float * hdpi_out, float * vdpi_out) 258{ 259 const SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata; 260 const SDL_VideoData *videodata = (SDL_VideoData *)display->device->driverdata; 261 float hdpi = 0, vdpi = 0, ddpi = 0; 262 263 if (videodata->GetDpiForMonitor) { 264 UINT hdpi_uint, vdpi_uint; 265 // Windows 8.1+ codepath 266 if (videodata->GetDpiForMonitor(displaydata->MonitorHandle, MDT_EFFECTIVE_DPI, &hdpi_uint, &vdpi_uint) == S_OK) { 267 // GetDpiForMonitor docs promise to return the same hdpi/vdpi 268 hdpi = (float)hdpi_uint; 269 vdpi = (float)hdpi_uint; 270 ddpi = (float)hdpi_uint; 271 } else { 272 return SDL_SetError("GetDpiForMonitor failed"); 273 } 274 } else { 275 // Window 8.0 and below: same DPI for all monitors. 276 HDC hdc; 277 int hdpi_int, vdpi_int, hpoints, vpoints, hpix, vpix; 278 float hinches, vinches; 279 280 hdc = GetDC(NULL); 281 if (hdc == NULL) { 282 return SDL_SetError("GetDC failed"); 283 } 284 hdpi_int = GetDeviceCaps(hdc, LOGPIXELSX); 285 vdpi_int = GetDeviceCaps(hdc, LOGPIXELSY); 286 ReleaseDC(NULL, hdc); 287 288 hpoints = GetSystemMetrics(SM_CXVIRTUALSCREEN); 289 vpoints = GetSystemMetrics(SM_CYVIRTUALSCREEN); 290 291 hpix = MulDiv(hpoints, hdpi_int, 96); 292 vpix = MulDiv(vpoints, vdpi_int, 96); 293 294 hinches = (float)hpoints / 96.0f; 295 vinches = (float)vpoints / 96.0f; 296 297 hdpi = (float)hdpi_int; 298 vdpi = (float)vdpi_int; 299 ddpi = SDL_ComputeDiagonalDPI(hpix, vpix, hinches, vinches); 300 } 301 302 if (ddpi_out) { 303 *ddpi_out = ddpi; 304 } 305 if (hdpi_out) { 306 *hdpi_out = hdpi; 307 } 308 if (vdpi_out) { 309 *vdpi_out = vdpi; 310 } 311 312 return ddpi != 0.0f ? 0 : SDL_SetError("Couldn't get DPI"); 313} 314 315int 316WIN_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect) 317{ 318 const SDL_DisplayData *data = (const SDL_DisplayData *)display->driverdata; 319 MONITORINFO minfo; 320 BOOL rc; 321 322 SDL_zero(minfo); 323 minfo.cbSize = sizeof(MONITORINFO); 324 rc = GetMonitorInfo(data->MonitorHandle, &minfo); 325 326 if (!rc) { 327 return SDL_SetError("Couldn't find monitor data"); 328 } 329 330 rect->x = minfo.rcWork.left; 331 rect->y = minfo.rcWork.top; 332 rect->w = minfo.rcWork.right - minfo.rcWork.left; 333 rect->h = minfo.rcWork.bottom - minfo.rcWork.top; 334 335 return 0; 336} 337 338void 339WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display) 340{ 341 SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata; 342 DWORD i; 343 SDL_DisplayMode mode; 344 345 for (i = 0;; ++i) { 346 if (!WIN_GetDisplayMode(_this, data->DeviceName, i, &mode)) { 347 break; 348 } 349 if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) { 350 /* We don't support palettized modes now */ 351 SDL_free(mode.driverdata); 352 continue; 353 } 354 if (mode.format != SDL_PIXELFORMAT_UNKNOWN) { 355 if (!SDL_AddDisplayMode(display, &mode)) { 356 SDL_free(mode.driverdata); 357 } 358 } else { 359 SDL_free(mode.driverdata); 360 } 361 } 362} 363 364int 365WIN_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) 366{ 367 SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata; 368 SDL_DisplayModeData *data = (SDL_DisplayModeData *) mode->driverdata; 369 LONG status; 370 371 if (mode->driverdata == display->desktop_mode.driverdata) { 372 status = ChangeDisplaySettingsEx(displaydata->DeviceName, NULL, NULL, CDS_FULLSCREEN, NULL); 373 } else { 374 status = ChangeDisplaySettingsEx(displaydata->DeviceName, &data->DeviceMode, NULL, CDS_FULLSCREEN, NULL); 375 } 376 if (status != DISP_CHANGE_SUCCESSFUL) { 377 const char *reason = "Unknown reason"; 378 switch (status) { 379 case DISP_CHANGE_BADFLAGS: 380 reason = "DISP_CHANGE_BADFLAGS"; 381 break; 382 case DISP_CHANGE_BADMODE: 383 reason = "DISP_CHANGE_BADMODE"; 384 break; 385 case DISP_CHANGE_BADPARAM: 386 reason = "DISP_CHANGE_BADPARAM"; 387 break; 388 case DISP_CHANGE_FAILED: 389 reason = "DISP_CHANGE_FAILED"; 390 break; 391 } 392 return SDL_SetError("ChangeDisplaySettingsEx() failed: %s", reason); 393 } 394 EnumDisplaySettings(displaydata->DeviceName, ENUM_CURRENT_SETTINGS, &data->DeviceMode); 395 WIN_UpdateDisplayMode(_this, displaydata->DeviceName, ENUM_CURRENT_SETTINGS, mode); 396 return 0; 397} 398 399void 400WIN_QuitModes(_THIS) 401{ 402 /* All fullscreen windows should have restored modes by now */ 403} 404 405#endif /* SDL_VIDEO_DRIVER_WINDOWS */ 406 407/* vi: set ts=4 sw=4 expandtab: */ 408[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.