SDL  2.0
SDL_windowsmodes.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 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 
32 typedef struct _WIN_GetMonitorDPIData {
33  SDL_VideoData *vid_data;
35  SDL_DisplayModeData *mode_data;
36 } WIN_GetMonitorDPIData;
37 
38 static BOOL CALLBACK
39 WIN_GetMonitorDPI(HMONITOR hMonitor,
40  HDC hdcMonitor,
41  LPRECT lprcMonitor,
42  LPARAM dwData)
43 {
44  WIN_GetMonitorDPIData *data = (WIN_GetMonitorDPIData*) dwData;
45  UINT hdpi, vdpi;
46 
47  if (data->vid_data->GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &hdpi, &vdpi) == S_OK &&
48  hdpi > 0 &&
49  vdpi > 0) {
50  float hsize, vsize;
51 
52  data->mode_data->HorzDPI = (float)hdpi;
53  data->mode_data->VertDPI = (float)vdpi;
54 
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;
58 
59  data->mode_data->DiagDPI = SDL_ComputeDiagonalDPI( data->mode->w,
60  data->mode->h,
61  hsize,
62  vsize );
63 
64  // We can only handle one DPI per display mode so end the enumeration.
65  return FALSE;
66  }
67 
68  // We didn't get DPI information so keep going.
69  return TRUE;
70 }
71 
72 static SDL_bool
73 WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode)
74 {
76  SDL_DisplayModeData *data;
77  DEVMODE devmode;
78  HDC hdc;
79 
80  devmode.dmSize = sizeof(devmode);
81  devmode.dmDriverExtra = 0;
82  if (!EnumDisplaySettings(deviceName, index, &devmode)) {
83  return SDL_FALSE;
84  }
85 
86  data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
87  if (!data) {
88  return SDL_FALSE;
89  }
90  data->DeviceMode = devmode;
91  data->DeviceMode.dmFields =
92  (DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY |
93  DM_DISPLAYFLAGS);
94  data->ScaleX = 1.0f;
95  data->ScaleY = 1.0f;
96  data->DiagDPI = 0.0f;
97  data->HorzDPI = 0.0f;
98  data->VertDPI = 0.0f;
99 
100  /* Fill in the mode information */
102  mode->w = devmode.dmPelsWidth;
103  mode->h = devmode.dmPelsHeight;
104  mode->refresh_rate = devmode.dmDisplayFrequency;
105  mode->driverdata = data;
106 
107  if (index == ENUM_CURRENT_SETTINGS
108  && (hdc = CreateDC(deviceName, NULL, NULL, NULL)) != NULL) {
109  char bmi_data[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];
110  LPBITMAPINFO bmi;
111  HBITMAP hbm;
112  int logical_width = GetDeviceCaps( hdc, HORZRES );
113  int logical_height = GetDeviceCaps( hdc, VERTRES );
114 
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;
119 
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;
124  RECT monitor_rect;
125 
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);
134  } else {
135  // We don't have the Windows 8.1 routine so just
136  // get system DPI.
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;
141  } else {
142  data->DiagDPI = SDL_ComputeDiagonalDPI( mode->w,
143  mode->h,
144  (float)GetDeviceCaps( hdc, HORZSIZE ) / 25.4f,
145  (float)GetDeviceCaps( hdc, VERTSIZE ) / 25.4f );
146  }
147  }
148 
149  SDL_zero(bmi_data);
150  bmi = (LPBITMAPINFO) bmi_data;
151  bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
152 
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);
156  DeleteObject(hbm);
157  DeleteDC(hdc);
158  if (bmi->bmiHeader.biCompression == BI_BITFIELDS) {
159  switch (*(Uint32 *) bmi->bmiColors) {
160  case 0x00FF0000:
162  break;
163  case 0x000000FF:
165  break;
166  case 0xF800:
168  break;
169  case 0x7C00:
171  break;
172  }
173  } else if (bmi->bmiHeader.biBitCount == 8) {
175  } else if (bmi->bmiHeader.biBitCount == 4) {
177  }
178  } else {
179  /* FIXME: Can we tell what this will be? */
180  if ((devmode.dmFields & DM_BITSPERPEL) == DM_BITSPERPEL) {
181  switch (devmode.dmBitsPerPel) {
182  case 32:
184  break;
185  case 24:
187  break;
188  case 16:
190  break;
191  case 15:
193  break;
194  case 8:
196  break;
197  case 4:
199  break;
200  }
201  }
202  }
203  return SDL_TRUE;
204 }
205 
206 static SDL_bool
207 WIN_AddDisplay(_THIS, LPTSTR DeviceName)
208 {
209  SDL_VideoDisplay display;
210  SDL_DisplayData *displaydata;
212  DISPLAY_DEVICE device;
213 
214 #ifdef DEBUG_MODES
215  printf("Display: %s\n", WIN_StringToUTF8(DeviceName));
216 #endif
217  if (!WIN_GetDisplayMode(_this, DeviceName, ENUM_CURRENT_SETTINGS, &mode)) {
218  return SDL_FALSE;
219  }
220 
221  displaydata = (SDL_DisplayData *) SDL_malloc(sizeof(*displaydata));
222  if (!displaydata) {
223  return SDL_FALSE;
224  }
225  SDL_memcpy(displaydata->DeviceName, DeviceName,
226  sizeof(displaydata->DeviceName));
227 
228  SDL_zero(display);
229  device.cb = sizeof(device);
230  if (EnumDisplayDevices(DeviceName, 0, &device, 0)) {
231  display.name = WIN_StringToUTF8(device.DeviceString);
232  }
233  display.desktop_mode = mode;
234  display.current_mode = mode;
235  display.driverdata = displaydata;
236  SDL_AddVideoDisplay(&display);
237  SDL_free(display.name);
238  return SDL_TRUE;
239 }
240 
241 int
243 {
244  int pass;
245  DWORD i, j, count;
246  DISPLAY_DEVICE device;
247 
248  device.cb = sizeof(device);
249 
250  /* Get the primary display in the first pass */
251  for (pass = 0; pass < 2; ++pass) {
252  for (i = 0; ; ++i) {
253  TCHAR DeviceName[32];
254 
255  if (!EnumDisplayDevices(NULL, i, &device, 0)) {
256  break;
257  }
258  if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) {
259  continue;
260  }
261  if (pass == 0) {
262  if (!(device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) {
263  continue;
264  }
265  } else {
266  if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
267  continue;
268  }
269  }
270  SDL_memcpy(DeviceName, device.DeviceName, sizeof(DeviceName));
271 #ifdef DEBUG_MODES
272  printf("Device: %s\n", WIN_StringToUTF8(DeviceName));
273 #endif
274  count = 0;
275  for (j = 0; ; ++j) {
276  if (!EnumDisplayDevices(DeviceName, j, &device, 0)) {
277  break;
278  }
279  if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) {
280  continue;
281  }
282  if (pass == 0) {
283  if (!(device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) {
284  continue;
285  }
286  } else {
287  if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
288  continue;
289  }
290  }
291  count += WIN_AddDisplay(_this, device.DeviceName);
292  }
293  if (count == 0) {
294  WIN_AddDisplay(_this, DeviceName);
295  }
296  }
297  }
298  if (_this->num_displays == 0) {
299  return SDL_SetError("No displays available");
300  }
301  return 0;
302 }
303 
304 int
306 {
308 
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);
313 
314  return 0;
315 }
316 
317 int
318 WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi)
319 {
321 
322  if (ddpi) {
323  *ddpi = data->DiagDPI;
324  }
325  if (hdpi) {
326  *hdpi = data->HorzDPI;
327  }
328  if (vdpi) {
329  *vdpi = data->VertDPI;
330  }
331 
332  return data->DiagDPI != 0.0f ? 0 : -1;
333 }
334 
335 void
337 {
338  SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
339  DWORD i;
340  SDL_DisplayMode mode;
341 
342  for (i = 0;; ++i) {
343  if (!WIN_GetDisplayMode(_this, data->DeviceName, i, &mode)) {
344  break;
345  }
346  if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
347  /* We don't support palettized modes now */
348  SDL_free(mode.driverdata);
349  continue;
350  }
351  if (mode.format != SDL_PIXELFORMAT_UNKNOWN) {
352  if (!SDL_AddDisplayMode(display, &mode)) {
353  SDL_free(mode.driverdata);
354  }
355  } else {
356  SDL_free(mode.driverdata);
357  }
358  }
359 }
360 
361 int
363 {
364  SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
366  LONG status;
367 
368  if (mode->driverdata == display->desktop_mode.driverdata) {
369  status = ChangeDisplaySettingsEx(displaydata->DeviceName, NULL, NULL, 0, NULL);
370  } else {
371  status = ChangeDisplaySettingsEx(displaydata->DeviceName, &data->DeviceMode, NULL, CDS_FULLSCREEN, NULL);
372  }
373  if (status != DISP_CHANGE_SUCCESSFUL) {
374  const char *reason = "Unknown reason";
375  switch (status) {
376  case DISP_CHANGE_BADFLAGS:
377  reason = "DISP_CHANGE_BADFLAGS";
378  break;
379  case DISP_CHANGE_BADMODE:
380  reason = "DISP_CHANGE_BADMODE";
381  break;
382  case DISP_CHANGE_BADPARAM:
383  reason = "DISP_CHANGE_BADPARAM";
384  break;
385  case DISP_CHANGE_FAILED:
386  reason = "DISP_CHANGE_FAILED";
387  break;
388  }
389  return SDL_SetError("ChangeDisplaySettingsEx() failed: %s", reason);
390  }
391  EnumDisplaySettings(displaydata->DeviceName, ENUM_CURRENT_SETTINGS, &data->DeviceMode);
392  return 0;
393 }
394 
395 void
397 {
398  /* All fullscreen windows should have restored modes by now */
399 }
400 
401 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
402 
403 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_ceil
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:155
void WIN_QuitModes(_THIS)
#define SDL_ISPIXELFORMAT_INDEXED(format)
Definition: SDL_pixels.h:133
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1564
SDL_Rect rect
Definition: testrelative.c:27
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
The structure that defines a display mode.
Definition: SDL_video.h:53
GLfloat f
int WIN_InitModes(_THIS)
int SDL_AddVideoDisplay(const SDL_VideoDisplay *display)
Definition: SDL_video.c:593
static SDL_VideoDevice * _this
Definition: SDL_video.c:114
SDL_bool
Definition: SDL_stdinc.h:126
void WIN_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
TCHAR DeviceName[32]
#define SDL_memcpy
int WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)
#define _THIS
void SDL_free(void *mem)
void * driverdata
Definition: SDL_video.h:59
#define TRUE
Definition: edid-parse.c:31
int WIN_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
SDL_DisplayMode current_mode
Definition: SDL_sysvideo.h:127
GLenum mode
#define WIN_StringToUTF8(S)
Definition: SDL_windows.h:45
#define SDL_zero(x)
Definition: SDL_stdinc.h:355
int x
Definition: SDL_rect.h:66
#define S_OK
Definition: SDL_directx.h:47
int w
Definition: SDL_rect.h:67
GLuint index
#define BI_BITFIELDS
Definition: SDL_bmp.c:47
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:42
#define NULL
Definition: begin_code.h:143
SDL_DisplayMode desktop_mode
Definition: SDL_sysvideo.h:126
#define SDL_SetError
int h
Definition: SDL_rect.h:67
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:709
int WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay *display, float *ddpi, float *hdpi, float *vdpi)
#define SDL_malloc
Uint32 format
Definition: SDL_video.h:55
#define FALSE
Definition: edid-parse.c:32
int y
Definition: SDL_rect.h:66
float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches)
Definition: SDL_video.c:3649
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
Definition: SDL_x11sym.h:42