2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "../../SDL_internal.h"
23 #if SDL_VIDEO_DRIVER_WINDOWS
25 #include "SDL_windowsvideo.h"
27 /* Windows CE compatibility */
28 #ifndef CDS_FULLSCREEN
29 #define CDS_FULLSCREEN 0
32 typedef struct _WIN_GetMonitorDPIData {
33 SDL_VideoData *vid_data;
34 SDL_DisplayMode *mode;
35 SDL_DisplayModeData *mode_data;
36 } WIN_GetMonitorDPIData;
39 WIN_GetMonitorDPI(HMONITOR hMonitor,
44 WIN_GetMonitorDPIData *data = (WIN_GetMonitorDPIData*) dwData;
47 if (data->vid_data->GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &hdpi, &vdpi) == S_OK &&
52 data->mode_data->HorzDPI = (float)hdpi;
53 data->mode_data->VertDPI = (float)vdpi;
55 // Figure out the monitor size and compute the diagonal DPI.
56 hsize = data->mode->w / data->mode_data->HorzDPI;
57 vsize = data->mode->h / data->mode_data->VertDPI;
59 data->mode_data->DiagDPI = SDL_ComputeDiagonalDPI( data->mode->w,
64 // We can only handle one DPI per display mode so end the enumeration.
68 // We didn't get DPI information so keep going.
73 WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode)
75 SDL_VideoData *vid_data = (SDL_VideoData *) _this->driverdata;
76 SDL_DisplayModeData *data;
80 devmode.dmSize = sizeof(devmode);
81 devmode.dmDriverExtra = 0;
82 if (!EnumDisplaySettings(deviceName, index, &devmode)) {
86 data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
90 data->DeviceMode = devmode;
91 data->DeviceMode.dmFields =
92 (DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY |
100 /* Fill in the mode information */
101 mode->format = SDL_PIXELFORMAT_UNKNOWN;
102 mode->w = devmode.dmPelsWidth;
103 mode->h = devmode.dmPelsHeight;
104 mode->refresh_rate = devmode.dmDisplayFrequency;
105 mode->driverdata = data;
107 if (index == ENUM_CURRENT_SETTINGS
108 && (hdc = CreateDC(deviceName, NULL, NULL, NULL)) != NULL) {
109 char bmi_data[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];
112 int logical_width = GetDeviceCaps( hdc, HORZRES );
113 int logical_height = GetDeviceCaps( hdc, VERTRES );
115 data->ScaleX = (float)logical_width / devmode.dmPelsWidth;
116 data->ScaleY = (float)logical_height / devmode.dmPelsHeight;
117 mode->w = logical_width;
118 mode->h = logical_height;
120 // WIN_GetMonitorDPI needs mode->w and mode->h
121 // so only call after those are set.
122 if (vid_data->GetDpiForMonitor) {
123 WIN_GetMonitorDPIData dpi_data;
126 dpi_data.vid_data = vid_data;
127 dpi_data.mode = mode;
128 dpi_data.mode_data = data;
129 monitor_rect.left = devmode.dmPosition.x;
130 monitor_rect.top = devmode.dmPosition.y;
131 monitor_rect.right = monitor_rect.left + 1;
132 monitor_rect.bottom = monitor_rect.top + 1;
133 EnumDisplayMonitors(NULL, &monitor_rect, WIN_GetMonitorDPI, (LPARAM)&dpi_data);
135 // We don't have the Windows 8.1 routine so just
137 data->HorzDPI = (float)GetDeviceCaps( hdc, LOGPIXELSX );
138 data->VertDPI = (float)GetDeviceCaps( hdc, LOGPIXELSY );
139 if (data->HorzDPI == data->VertDPI) {
140 data->DiagDPI = data->HorzDPI;
142 data->DiagDPI = SDL_ComputeDiagonalDPI( mode->w,
144 (float)GetDeviceCaps( hdc, HORZSIZE ) / 25.4f,
145 (float)GetDeviceCaps( hdc, VERTSIZE ) / 25.4f );
150 bmi = (LPBITMAPINFO) bmi_data;
151 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
153 hbm = CreateCompatibleBitmap(hdc, 1, 1);
154 GetDIBits(hdc, hbm, 0, 1, NULL, bmi, DIB_RGB_COLORS);
155 GetDIBits(hdc, hbm, 0, 1, NULL, bmi, DIB_RGB_COLORS);
158 if (bmi->bmiHeader.biCompression == BI_BITFIELDS) {
159 switch (*(Uint32 *) bmi->bmiColors) {
161 mode->format = SDL_PIXELFORMAT_RGB888;
164 mode->format = SDL_PIXELFORMAT_BGR888;
167 mode->format = SDL_PIXELFORMAT_RGB565;
170 mode->format = SDL_PIXELFORMAT_RGB555;
173 } else if (bmi->bmiHeader.biBitCount == 8) {
174 mode->format = SDL_PIXELFORMAT_INDEX8;
175 } else if (bmi->bmiHeader.biBitCount == 4) {
176 mode->format = SDL_PIXELFORMAT_INDEX4LSB;
179 /* FIXME: Can we tell what this will be? */
180 if ((devmode.dmFields & DM_BITSPERPEL) == DM_BITSPERPEL) {
181 switch (devmode.dmBitsPerPel) {
183 mode->format = SDL_PIXELFORMAT_RGB888;
186 mode->format = SDL_PIXELFORMAT_RGB24;
189 mode->format = SDL_PIXELFORMAT_RGB565;
192 mode->format = SDL_PIXELFORMAT_RGB555;
195 mode->format = SDL_PIXELFORMAT_INDEX8;
198 mode->format = SDL_PIXELFORMAT_INDEX4LSB;
207 WIN_AddDisplay(_THIS, LPTSTR DeviceName)
209 SDL_VideoDisplay display;
210 SDL_DisplayData *displaydata;
211 SDL_DisplayMode mode;
212 DISPLAY_DEVICE device;
215 printf("Display: %s\n", WIN_StringToUTF8(DeviceName));
217 if (!WIN_GetDisplayMode(_this, DeviceName, ENUM_CURRENT_SETTINGS, &mode)) {
221 displaydata = (SDL_DisplayData *) SDL_malloc(sizeof(*displaydata));
225 SDL_memcpy(displaydata->DeviceName, DeviceName,
226 sizeof(displaydata->DeviceName));
229 device.cb = sizeof(device);
230 if (EnumDisplayDevices(DeviceName, 0, &device, 0)) {
231 display.name = WIN_StringToUTF8(device.DeviceString);
233 display.desktop_mode = mode;
234 display.current_mode = mode;
235 display.driverdata = displaydata;
236 SDL_AddVideoDisplay(&display);
237 SDL_free(display.name);
246 DISPLAY_DEVICE device;
248 device.cb = sizeof(device);
250 /* Get the primary display in the first pass */
251 for (pass = 0; pass < 2; ++pass) {
253 TCHAR DeviceName[32];
255 if (!EnumDisplayDevices(NULL, i, &device, 0)) {
258 if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) {
262 if (!(device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) {
266 if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
270 SDL_memcpy(DeviceName, device.DeviceName, sizeof(DeviceName));
272 printf("Device: %s\n", WIN_StringToUTF8(DeviceName));
276 if (!EnumDisplayDevices(DeviceName, j, &device, 0)) {
279 if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) {
283 if (!(device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) {
287 if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
291 count += WIN_AddDisplay(_this, device.DeviceName);
294 WIN_AddDisplay(_this, DeviceName);
298 if (_this->num_displays == 0) {
299 return SDL_SetError("No displays available");
305 WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
307 SDL_DisplayModeData *data = (SDL_DisplayModeData *) display->current_mode.driverdata;
309 rect->x = (int)SDL_ceil(data->DeviceMode.dmPosition.x * data->ScaleX);
310 rect->y = (int)SDL_ceil(data->DeviceMode.dmPosition.y * data->ScaleY);
311 rect->w = (int)SDL_ceil(data->DeviceMode.dmPelsWidth * data->ScaleX);
312 rect->h = (int)SDL_ceil(data->DeviceMode.dmPelsHeight * data->ScaleY);
318 WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi)
320 SDL_DisplayModeData *data = (SDL_DisplayModeData *) display->current_mode.driverdata;
323 *ddpi = data->DiagDPI;
326 *hdpi = data->HorzDPI;
329 *vdpi = data->VertDPI;
332 return data->DiagDPI != 0.0f ? 0 : -1;
336 WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
338 SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
340 SDL_DisplayMode mode;
343 if (!WIN_GetDisplayMode(_this, data->DeviceName, i, &mode)) {
346 if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
347 /* We don't support palettized modes now */
348 SDL_free(mode.driverdata);
351 if (mode.format != SDL_PIXELFORMAT_UNKNOWN) {
352 if (!SDL_AddDisplayMode(display, &mode)) {
353 SDL_free(mode.driverdata);
356 SDL_free(mode.driverdata);
362 WIN_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
364 SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
365 SDL_DisplayModeData *data = (SDL_DisplayModeData *) mode->driverdata;
368 if (mode->driverdata == display->desktop_mode.driverdata) {
369 status = ChangeDisplaySettingsEx(displaydata->DeviceName, NULL, NULL, 0, NULL);
371 status = ChangeDisplaySettingsEx(displaydata->DeviceName, &data->DeviceMode, NULL, CDS_FULLSCREEN, NULL);
373 if (status != DISP_CHANGE_SUCCESSFUL) {
374 const char *reason = "Unknown reason";
376 case DISP_CHANGE_BADFLAGS:
377 reason = "DISP_CHANGE_BADFLAGS";
379 case DISP_CHANGE_BADMODE:
380 reason = "DISP_CHANGE_BADMODE";
382 case DISP_CHANGE_BADPARAM:
383 reason = "DISP_CHANGE_BADPARAM";
385 case DISP_CHANGE_FAILED:
386 reason = "DISP_CHANGE_FAILED";
389 return SDL_SetError("ChangeDisplaySettingsEx() failed: %s", reason);
391 EnumDisplaySettings(displaydata->DeviceName, ENUM_CURRENT_SETTINGS, &data->DeviceMode);
398 /* All fullscreen windows should have restored modes by now */
401 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
403 /* vi: set ts=4 sw=4 expandtab: */