SDL_windowsmodes.c (9938B)
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 "SDL_windowsvideo.h" 26 27/* Windows CE compatibility */ 28#ifndef CDS_FULLSCREEN 29#define CDS_FULLSCREEN 0 30#endif 31 32static SDL_bool 33WIN_GetDisplayMode(LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode) 34{ 35 SDL_DisplayModeData *data; 36 DEVMODE devmode; 37 HDC hdc; 38 39 devmode.dmSize = sizeof(devmode); 40 devmode.dmDriverExtra = 0; 41 if (!EnumDisplaySettings(deviceName, index, &devmode)) { 42 return SDL_FALSE; 43 } 44 45 data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data)); 46 if (!data) { 47 return SDL_FALSE; 48 } 49 data->DeviceMode = devmode; 50 data->DeviceMode.dmFields = 51 (DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | 52 DM_DISPLAYFLAGS); 53 data->ScaleX = 1.0f; 54 data->ScaleY = 1.0f; 55 56 /* Fill in the mode information */ 57 mode->format = SDL_PIXELFORMAT_UNKNOWN; 58 mode->w = devmode.dmPelsWidth; 59 mode->h = devmode.dmPelsHeight; 60 mode->refresh_rate = devmode.dmDisplayFrequency; 61 mode->driverdata = data; 62 63 if (index == ENUM_CURRENT_SETTINGS 64 && (hdc = CreateDC(deviceName, NULL, NULL, NULL)) != NULL) { 65 char bmi_data[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)]; 66 LPBITMAPINFO bmi; 67 HBITMAP hbm; 68 int logical_width = GetDeviceCaps( hdc, HORZRES ); 69 int logical_height = GetDeviceCaps( hdc, VERTRES ); 70 71 data->ScaleX = (float)logical_width / devmode.dmPelsWidth; 72 data->ScaleY = (float)logical_height / devmode.dmPelsHeight; 73 mode->w = logical_width; 74 mode->h = logical_height; 75 76 SDL_zero(bmi_data); 77 bmi = (LPBITMAPINFO) bmi_data; 78 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 79 80 hbm = CreateCompatibleBitmap(hdc, 1, 1); 81 GetDIBits(hdc, hbm, 0, 1, NULL, bmi, DIB_RGB_COLORS); 82 GetDIBits(hdc, hbm, 0, 1, NULL, bmi, DIB_RGB_COLORS); 83 DeleteObject(hbm); 84 DeleteDC(hdc); 85 if (bmi->bmiHeader.biCompression == BI_BITFIELDS) { 86 switch (*(Uint32 *) bmi->bmiColors) { 87 case 0x00FF0000: 88 mode->format = SDL_PIXELFORMAT_RGB888; 89 break; 90 case 0x000000FF: 91 mode->format = SDL_PIXELFORMAT_BGR888; 92 break; 93 case 0xF800: 94 mode->format = SDL_PIXELFORMAT_RGB565; 95 break; 96 case 0x7C00: 97 mode->format = SDL_PIXELFORMAT_RGB555; 98 break; 99 } 100 } else if (bmi->bmiHeader.biBitCount == 8) { 101 mode->format = SDL_PIXELFORMAT_INDEX8; 102 } else if (bmi->bmiHeader.biBitCount == 4) { 103 mode->format = SDL_PIXELFORMAT_INDEX4LSB; 104 } 105 } else { 106 /* FIXME: Can we tell what this will be? */ 107 if ((devmode.dmFields & DM_BITSPERPEL) == DM_BITSPERPEL) { 108 switch (devmode.dmBitsPerPel) { 109 case 32: 110 mode->format = SDL_PIXELFORMAT_RGB888; 111 break; 112 case 24: 113 mode->format = SDL_PIXELFORMAT_RGB24; 114 break; 115 case 16: 116 mode->format = SDL_PIXELFORMAT_RGB565; 117 break; 118 case 15: 119 mode->format = SDL_PIXELFORMAT_RGB555; 120 break; 121 case 8: 122 mode->format = SDL_PIXELFORMAT_INDEX8; 123 break; 124 case 4: 125 mode->format = SDL_PIXELFORMAT_INDEX4LSB; 126 break; 127 } 128 } 129 } 130 return SDL_TRUE; 131} 132 133static SDL_bool 134WIN_AddDisplay(LPTSTR DeviceName) 135{ 136 SDL_VideoDisplay display; 137 SDL_DisplayData *displaydata; 138 SDL_DisplayMode mode; 139 DISPLAY_DEVICE device; 140 141#ifdef DEBUG_MODES 142 printf("Display: %s\n", WIN_StringToUTF8(DeviceName)); 143#endif 144 if (!WIN_GetDisplayMode(DeviceName, ENUM_CURRENT_SETTINGS, &mode)) { 145 return SDL_FALSE; 146 } 147 148 displaydata = (SDL_DisplayData *) SDL_malloc(sizeof(*displaydata)); 149 if (!displaydata) { 150 return SDL_FALSE; 151 } 152 SDL_memcpy(displaydata->DeviceName, DeviceName, 153 sizeof(displaydata->DeviceName)); 154 155 SDL_zero(display); 156 device.cb = sizeof(device); 157 if (EnumDisplayDevices(DeviceName, 0, &device, 0)) { 158 display.name = WIN_StringToUTF8(device.DeviceString); 159 } 160 display.desktop_mode = mode; 161 display.current_mode = mode; 162 display.driverdata = displaydata; 163 SDL_AddVideoDisplay(&display); 164 SDL_free(display.name); 165 return SDL_TRUE; 166} 167 168int 169WIN_InitModes(_THIS) 170{ 171 int pass; 172 DWORD i, j, count; 173 DISPLAY_DEVICE device; 174 175 device.cb = sizeof(device); 176 177 /* Get the primary display in the first pass */ 178 for (pass = 0; pass < 2; ++pass) { 179 for (i = 0; ; ++i) { 180 TCHAR DeviceName[32]; 181 182 if (!EnumDisplayDevices(NULL, i, &device, 0)) { 183 break; 184 } 185 if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) { 186 continue; 187 } 188 if (pass == 0) { 189 if (!(device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) { 190 continue; 191 } 192 } else { 193 if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) { 194 continue; 195 } 196 } 197 SDL_memcpy(DeviceName, device.DeviceName, sizeof(DeviceName)); 198#ifdef DEBUG_MODES 199 printf("Device: %s\n", WIN_StringToUTF8(DeviceName)); 200#endif 201 count = 0; 202 for (j = 0; ; ++j) { 203 if (!EnumDisplayDevices(DeviceName, j, &device, 0)) { 204 break; 205 } 206 if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) { 207 continue; 208 } 209 if (pass == 0) { 210 if (!(device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) { 211 continue; 212 } 213 } else { 214 if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) { 215 continue; 216 } 217 } 218 count += WIN_AddDisplay(device.DeviceName); 219 } 220 if (count == 0) { 221 WIN_AddDisplay(DeviceName); 222 } 223 } 224 } 225 if (_this->num_displays == 0) { 226 return SDL_SetError("No displays available"); 227 } 228 return 0; 229} 230 231int 232WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect) 233{ 234 SDL_DisplayModeData *data = (SDL_DisplayModeData *) display->current_mode.driverdata; 235 236 rect->x = (int)SDL_ceil(data->DeviceMode.dmPosition.x * data->ScaleX); 237 rect->y = (int)SDL_ceil(data->DeviceMode.dmPosition.y * data->ScaleY); 238 rect->w = (int)SDL_ceil(data->DeviceMode.dmPelsWidth * data->ScaleX); 239 rect->h = (int)SDL_ceil(data->DeviceMode.dmPelsHeight * data->ScaleY); 240 241 return 0; 242} 243 244void 245WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display) 246{ 247 SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata; 248 DWORD i; 249 SDL_DisplayMode mode; 250 251 for (i = 0;; ++i) { 252 if (!WIN_GetDisplayMode(data->DeviceName, i, &mode)) { 253 break; 254 } 255 if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) { 256 /* We don't support palettized modes now */ 257 SDL_free(mode.driverdata); 258 continue; 259 } 260 if (mode.format != SDL_PIXELFORMAT_UNKNOWN) { 261 if (!SDL_AddDisplayMode(display, &mode)) { 262 SDL_free(mode.driverdata); 263 } 264 } else { 265 SDL_free(mode.driverdata); 266 } 267 } 268} 269 270int 271WIN_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) 272{ 273 SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata; 274 SDL_DisplayModeData *data = (SDL_DisplayModeData *) mode->driverdata; 275 LONG status; 276 277 if (mode->driverdata == display->desktop_mode.driverdata) { 278 status = ChangeDisplaySettingsEx(displaydata->DeviceName, NULL, NULL, 0, NULL); 279 } else { 280 status = ChangeDisplaySettingsEx(displaydata->DeviceName, &data->DeviceMode, NULL, CDS_FULLSCREEN, NULL); 281 } 282 if (status != DISP_CHANGE_SUCCESSFUL) { 283 const char *reason = "Unknown reason"; 284 switch (status) { 285 case DISP_CHANGE_BADFLAGS: 286 reason = "DISP_CHANGE_BADFLAGS"; 287 break; 288 case DISP_CHANGE_BADMODE: 289 reason = "DISP_CHANGE_BADMODE"; 290 break; 291 case DISP_CHANGE_BADPARAM: 292 reason = "DISP_CHANGE_BADPARAM"; 293 break; 294 case DISP_CHANGE_FAILED: 295 reason = "DISP_CHANGE_FAILED"; 296 break; 297 } 298 return SDL_SetError("ChangeDisplaySettingsEx() failed: %s", reason); 299 } 300 EnumDisplaySettings(displaydata->DeviceName, ENUM_CURRENT_SETTINGS, &data->DeviceMode); 301 return 0; 302} 303 304void 305WIN_QuitModes(_THIS) 306{ 307 /* All fullscreen windows should have restored modes by now */ 308} 309 310#endif /* SDL_VIDEO_DRIVER_WINDOWS */ 311 312/* vi: set ts=4 sw=4 expandtab: */