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 #include "../../../include/SDL_assert.h"
27 
28 /* Windows CE compatibility */
29 #ifndef CDS_FULLSCREEN
30 #define CDS_FULLSCREEN 0
31 #endif
32 
33 typedef struct _WIN_GetMonitorDPIData {
34  SDL_VideoData *vid_data;
36  SDL_DisplayModeData *mode_data;
37 } WIN_GetMonitorDPIData;
38 
39 static BOOL CALLBACK
40 WIN_GetMonitorDPI(HMONITOR hMonitor,
41  HDC hdcMonitor,
42  LPRECT lprcMonitor,
43  LPARAM dwData)
44 {
45  WIN_GetMonitorDPIData *data = (WIN_GetMonitorDPIData*) dwData;
46  UINT hdpi, vdpi;
47 
48  if (data->vid_data->GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &hdpi, &vdpi) == S_OK &&
49  hdpi > 0 &&
50  vdpi > 0) {
51  float hsize, vsize;
52 
53  data->mode_data->HorzDPI = (float)hdpi;
54  data->mode_data->VertDPI = (float)vdpi;
55 
56  // Figure out the monitor size and compute the diagonal DPI.
57  hsize = data->mode->w / data->mode_data->HorzDPI;
58  vsize = data->mode->h / data->mode_data->VertDPI;
59 
60  data->mode_data->DiagDPI = SDL_ComputeDiagonalDPI( data->mode->w,
61  data->mode->h,
62  hsize,
63  vsize );
64 
65  // We can only handle one DPI per display mode so end the enumeration.
66  return FALSE;
67  }
68 
69  // We didn't get DPI information so keep going.
70  return TRUE;
71 }
72 
73 static void
74 WIN_UpdateDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode)
75 {
78  HDC hdc;
79 
80  data->DeviceMode.dmFields =
81  (DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY |
82  DM_DISPLAYFLAGS);
83 
84  if (index == ENUM_CURRENT_SETTINGS
85  && (hdc = CreateDC(deviceName, NULL, NULL, NULL)) != NULL) {
86  char bmi_data[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];
87  LPBITMAPINFO bmi;
88  HBITMAP hbm;
89  int logical_width = GetDeviceCaps( hdc, HORZRES );
90  int logical_height = GetDeviceCaps( hdc, VERTRES );
91 
92  data->ScaleX = (float)logical_width / data->DeviceMode.dmPelsWidth;
93  data->ScaleY = (float)logical_height / data->DeviceMode.dmPelsHeight;
94  mode->w = logical_width;
95  mode->h = logical_height;
96 
97  // WIN_GetMonitorDPI needs mode->w and mode->h
98  // so only call after those are set.
99  if (vid_data->GetDpiForMonitor) {
100  WIN_GetMonitorDPIData dpi_data;
101  RECT monitor_rect;
102 
103  dpi_data.vid_data = vid_data;
104  dpi_data.mode = mode;
105  dpi_data.mode_data = data;
106  monitor_rect.left = data->DeviceMode.dmPosition.x;
107  monitor_rect.top = data->DeviceMode.dmPosition.y;
108  monitor_rect.right = monitor_rect.left + 1;
109  monitor_rect.bottom = monitor_rect.top + 1;
110  EnumDisplayMonitors(NULL, &monitor_rect, WIN_GetMonitorDPI, (LPARAM)&dpi_data);
111  } else {
112  // We don't have the Windows 8.1 routine so just
113  // get system DPI.
114  data->HorzDPI = (float)GetDeviceCaps( hdc, LOGPIXELSX );
115  data->VertDPI = (float)GetDeviceCaps( hdc, LOGPIXELSY );
116  if (data->HorzDPI == data->VertDPI) {
117  data->DiagDPI = data->HorzDPI;
118  } else {
119  data->DiagDPI = SDL_ComputeDiagonalDPI( mode->w,
120  mode->h,
121  (float)GetDeviceCaps( hdc, HORZSIZE ) / 25.4f,
122  (float)GetDeviceCaps( hdc, VERTSIZE ) / 25.4f );
123  }
124  }
125 
126  SDL_zero(bmi_data);
127  bmi = (LPBITMAPINFO) bmi_data;
128  bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
129 
130  hbm = CreateCompatibleBitmap(hdc, 1, 1);
131  GetDIBits(hdc, hbm, 0, 1, NULL, bmi, DIB_RGB_COLORS);
132  GetDIBits(hdc, hbm, 0, 1, NULL, bmi, DIB_RGB_COLORS);
133  DeleteObject(hbm);
134  DeleteDC(hdc);
135  if (bmi->bmiHeader.biCompression == BI_BITFIELDS) {
136  switch (*(Uint32 *) bmi->bmiColors) {
137  case 0x00FF0000:
139  break;
140  case 0x000000FF:
142  break;
143  case 0xF800:
145  break;
146  case 0x7C00:
148  break;
149  }
150  } else if (bmi->bmiHeader.biBitCount == 8) {
152  } else if (bmi->bmiHeader.biBitCount == 4) {
154  }
155  } else if (mode->format == SDL_PIXELFORMAT_UNKNOWN) {
156  /* FIXME: Can we tell what this will be? */
157  if ((data->DeviceMode.dmFields & DM_BITSPERPEL) == DM_BITSPERPEL) {
158  switch (data->DeviceMode.dmBitsPerPel) {
159  case 32:
161  break;
162  case 24:
164  break;
165  case 16:
167  break;
168  case 15:
170  break;
171  case 8:
173  break;
174  case 4:
176  break;
177  }
178  }
179  }
180 }
181 
182 static SDL_bool
183 WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode)
184 {
186  DEVMODE devmode;
187 
188  devmode.dmSize = sizeof(devmode);
189  devmode.dmDriverExtra = 0;
190  if (!EnumDisplaySettings(deviceName, index, &devmode)) {
191  return SDL_FALSE;
192  }
193 
194  data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
195  if (!data) {
196  return SDL_FALSE;
197  }
198 
199  mode->driverdata = data;
200  data->DeviceMode = devmode;
201 
202  /* Default basic information */
203  data->ScaleX = 1.0f;
204  data->ScaleY = 1.0f;
205  data->DiagDPI = 0.0f;
206  data->HorzDPI = 0.0f;
207  data->VertDPI = 0.0f;
208 
210  mode->w = data->DeviceMode.dmPelsWidth;
211  mode->h = data->DeviceMode.dmPelsHeight;
212  mode->refresh_rate = data->DeviceMode.dmDisplayFrequency;
213 
214  /* Fill in the mode information */
215  WIN_UpdateDisplayMode(_this, deviceName, index, mode);
216  return SDL_TRUE;
217 }
218 
219 static SDL_bool
220 WIN_AddDisplay(_THIS, LPTSTR DeviceName)
221 {
222  SDL_VideoDisplay display;
223  SDL_DisplayData *displaydata;
225  DISPLAY_DEVICE device;
226 
227 #ifdef DEBUG_MODES
228  printf("Display: %s\n", WIN_StringToUTF8(DeviceName));
229 #endif
230  if (!WIN_GetDisplayMode(_this, DeviceName, ENUM_CURRENT_SETTINGS, &mode)) {
231  return SDL_FALSE;
232  }
233 
234  displaydata = (SDL_DisplayData *) SDL_malloc(sizeof(*displaydata));
235  if (!displaydata) {
236  return SDL_FALSE;
237  }
238  SDL_memcpy(displaydata->DeviceName, DeviceName,
239  sizeof(displaydata->DeviceName));
240 
241  SDL_zero(display);
242  device.cb = sizeof(device);
243  if (EnumDisplayDevices(DeviceName, 0, &device, 0)) {
244  display.name = WIN_StringToUTF8(device.DeviceString);
245  }
246  display.desktop_mode = mode;
247  display.current_mode = mode;
248  display.driverdata = displaydata;
249  SDL_AddVideoDisplay(&display);
250  SDL_free(display.name);
251  return SDL_TRUE;
252 }
253 
254 int
256 {
257  int pass;
258  DWORD i, j, count;
259  DISPLAY_DEVICE device;
260 
261  device.cb = sizeof(device);
262 
263  /* Get the primary display in the first pass */
264  for (pass = 0; pass < 2; ++pass) {
265  for (i = 0; ; ++i) {
266  TCHAR DeviceName[32];
267 
268  if (!EnumDisplayDevices(NULL, i, &device, 0)) {
269  break;
270  }
271  if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) {
272  continue;
273  }
274  if (pass == 0) {
275  if (!(device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) {
276  continue;
277  }
278  } else {
279  if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
280  continue;
281  }
282  }
283  SDL_memcpy(DeviceName, device.DeviceName, sizeof(DeviceName));
284 #ifdef DEBUG_MODES
285  printf("Device: %s\n", WIN_StringToUTF8(DeviceName));
286 #endif
287  count = 0;
288  for (j = 0; ; ++j) {
289  if (!EnumDisplayDevices(DeviceName, j, &device, 0)) {
290  break;
291  }
292  if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) {
293  continue;
294  }
295  if (pass == 0) {
296  if (!(device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) {
297  continue;
298  }
299  } else {
300  if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
301  continue;
302  }
303  }
304  count += WIN_AddDisplay(_this, device.DeviceName);
305  }
306  if (count == 0) {
307  WIN_AddDisplay(_this, DeviceName);
308  }
309  }
310  }
311  if (_this->num_displays == 0) {
312  return SDL_SetError("No displays available");
313  }
314  return 0;
315 }
316 
317 int
319 {
321 
322  rect->x = (int)SDL_ceil(data->DeviceMode.dmPosition.x * data->ScaleX);
323  rect->y = (int)SDL_ceil(data->DeviceMode.dmPosition.y * data->ScaleY);
324  rect->w = (int)SDL_ceil(data->DeviceMode.dmPelsWidth * data->ScaleX);
325  rect->h = (int)SDL_ceil(data->DeviceMode.dmPelsHeight * data->ScaleY);
326 
327  return 0;
328 }
329 
330 int
331 WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi)
332 {
334 
335  if (ddpi) {
336  *ddpi = data->DiagDPI;
337  }
338  if (hdpi) {
339  *hdpi = data->HorzDPI;
340  }
341  if (vdpi) {
342  *vdpi = data->VertDPI;
343  }
344 
345  return data->DiagDPI != 0.0f ? 0 : SDL_SetError("Couldn't get DPI");
346 }
347 
348 int
350 {
351  const SDL_DisplayModeData *data = (const SDL_DisplayModeData *) display->current_mode.driverdata;
352  const DEVMODE *pDevMode = &data->DeviceMode;
353  POINT pt = {
354  /* !!! FIXME: no scale, right? */
355  (LONG) (pDevMode->dmPosition.x + (pDevMode->dmPelsWidth / 2)),
356  (LONG) (pDevMode->dmPosition.y + (pDevMode->dmPelsHeight / 2))
357  };
358  HMONITOR hmon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
359  MONITORINFO minfo;
360  const RECT *work;
361  BOOL rc = FALSE;
362 
363  SDL_assert(hmon != NULL);
364 
365  if (hmon != NULL) {
366  SDL_zero(minfo);
367  minfo.cbSize = sizeof (MONITORINFO);
368  rc = GetMonitorInfo(hmon, &minfo);
369  SDL_assert(rc);
370  }
371 
372  if (!rc) {
373  return SDL_SetError("Couldn't find monitor data");
374  }
375 
376  work = &minfo.rcWork;
377  rect->x = (int)SDL_ceil(work->left * data->ScaleX);
378  rect->y = (int)SDL_ceil(work->top * data->ScaleY);
379  rect->w = (int)SDL_ceil((work->right - work->left) * data->ScaleX);
380  rect->h = (int)SDL_ceil((work->bottom - work->top) * data->ScaleY);
381 
382  return 0;
383 }
384 
385 void
387 {
388  SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
389  DWORD i;
390  SDL_DisplayMode mode;
391 
392  for (i = 0;; ++i) {
393  if (!WIN_GetDisplayMode(_this, data->DeviceName, i, &mode)) {
394  break;
395  }
396  if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
397  /* We don't support palettized modes now */
398  SDL_free(mode.driverdata);
399  continue;
400  }
401  if (mode.format != SDL_PIXELFORMAT_UNKNOWN) {
402  if (!SDL_AddDisplayMode(display, &mode)) {
403  SDL_free(mode.driverdata);
404  }
405  } else {
406  SDL_free(mode.driverdata);
407  }
408  }
409 }
410 
411 int
413 {
414  SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
416  LONG status;
417 
418  if (mode->driverdata == display->desktop_mode.driverdata) {
419  status = ChangeDisplaySettingsEx(displaydata->DeviceName, NULL, NULL, CDS_FULLSCREEN, NULL);
420  } else {
421  status = ChangeDisplaySettingsEx(displaydata->DeviceName, &data->DeviceMode, NULL, CDS_FULLSCREEN, NULL);
422  }
423  if (status != DISP_CHANGE_SUCCESSFUL) {
424  const char *reason = "Unknown reason";
425  switch (status) {
426  case DISP_CHANGE_BADFLAGS:
427  reason = "DISP_CHANGE_BADFLAGS";
428  break;
429  case DISP_CHANGE_BADMODE:
430  reason = "DISP_CHANGE_BADMODE";
431  break;
432  case DISP_CHANGE_BADPARAM:
433  reason = "DISP_CHANGE_BADPARAM";
434  break;
435  case DISP_CHANGE_FAILED:
436  reason = "DISP_CHANGE_FAILED";
437  break;
438  }
439  return SDL_SetError("ChangeDisplaySettingsEx() failed: %s", reason);
440  }
441  EnumDisplaySettings(displaydata->DeviceName, ENUM_CURRENT_SETTINGS, &data->DeviceMode);
442  WIN_UpdateDisplayMode(_this, displaydata->DeviceName, ENUM_CURRENT_SETTINGS, mode);
443  return 0;
444 }
445 
446 void
448 {
449  /* All fullscreen windows should have restored modes by now */
450 }
451 
452 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
453 
454 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_ceil
void WIN_QuitModes(_THIS)
#define SDL_ISPIXELFORMAT_INDEXED(format)
Definition: SDL_pixels.h:134
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
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:161
int WIN_InitModes(_THIS)
int SDL_AddVideoDisplay(const SDL_VideoDisplay *display)
Definition: SDL_video.c:591
static SDL_VideoDevice * _this
Definition: SDL_video.c:118
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:33
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:50
int WIN_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
SDL_DisplayMode current_mode
Definition: SDL_sysvideo.h:130
GLenum mode
#define WIN_StringToUTF8(S)
Definition: SDL_windows.h:45
#define SDL_zero(x)
Definition: SDL_stdinc.h:361
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:48
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:50
#define SDL_assert(condition)
Definition: SDL_assert.h:167
#define NULL
Definition: begin_code.h:143
SDL_bool
Definition: SDL_stdinc.h:130
SDL_DisplayMode desktop_mode
Definition: SDL_sysvideo.h:129
#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:728
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:34
int y
Definition: SDL_rect.h:66
float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches)
Definition: SDL_video.c:3783
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64
int WIN_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)