SDL  2.0
SDL_windowsmodes.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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 #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 
36 static void
37 WIN_UpdateDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode)
38 {
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_zeroa(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) {
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:
107  break;
108  }
109  }
110  }
111 }
112 
113 static SDL_bool
114 WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode)
115 {
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 
143 static SDL_bool
144 WIN_AddDisplay(_THIS, HMONITOR hMonitor, const MONITORINFOEX *info)
145 {
146  SDL_VideoDisplay display;
147  SDL_DisplayData *displaydata;
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 
180 typedef struct _WIN_AddDisplaysData {
181  SDL_VideoDevice *video_device;
182  SDL_bool want_primary;
183 } WIN_AddDisplaysData;
184 
185 static BOOL CALLBACK
186 WIN_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 
209 static void
210 WIN_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 
222 int
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 
233 int
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 
256 int
257 WIN_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 
315 int
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 
338 void
340 {
342  DWORD i;
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 
364 int
366 {
367  SDL_DisplayData *displaydata = (SDL_DisplayData *) display->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 
399 void
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: */
SDL_zero
#define SDL_zero(x)
Definition: SDL_stdinc.h:418
SDL_VideoDevice::driverdata
void * driverdata
Definition: SDL_sysvideo.h:389
SDL_VideoDisplay::name
char * name
Definition: SDL_sysvideo.h:128
MDT_EFFECTIVE_DPI
@ MDT_EFFECTIVE_DPI
Definition: SDL_windowsvideo.h:82
SDL_PIXELFORMAT_RGB888
@ SDL_PIXELFORMAT_RGB888
Definition: SDL_pixels.h:239
WIN_GetDisplayUsableBounds
int WIN_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)
NULL
#define NULL
Definition: begin_code.h:167
SDL_VideoDisplay::device
SDL_VideoDevice * device
Definition: SDL_sysvideo.h:138
TRUE
#define TRUE
Definition: edid-parse.c:33
mode
GLenum mode
Definition: SDL_opengl_glext.h:1125
SDL_PIXELFORMAT_BGR888
@ SDL_PIXELFORMAT_BGR888
Definition: SDL_pixels.h:245
WIN_InitModes
int WIN_InitModes(_THIS)
Uint32
uint32_t Uint32
Definition: SDL_stdinc.h:203
SDL_ISPIXELFORMAT_INDEXED
#define SDL_ISPIXELFORMAT_INDEXED(format)
Definition: SDL_pixels.h:134
SDL_PIXELFORMAT_RGB565
@ SDL_PIXELFORMAT_RGB565
Definition: SDL_pixels.h:227
SDL_VideoDisplay::desktop_mode
SDL_DisplayMode desktop_mode
Definition: SDL_sysvideo.h:132
index
GLuint index
Definition: SDL_opengl_glext.h:663
SDL_zeroa
#define SDL_zeroa(x)
Definition: SDL_stdinc.h:420
SDL_Rect::x
int x
Definition: SDL_rect.h:79
WIN_GetDisplayModes
void WIN_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
SDL_Rect::w
int w
Definition: SDL_rect.h:80
SDL_DisplayMode
The structure that defines a display mode.
Definition: SDL_video.h:54
SDL_AddDisplayMode
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:772
SDL_DisplayData::DeviceName
TCHAR DeviceName[32]
Definition: SDL_windowsmodes.h:28
SDL_memcpy
#define SDL_memcpy
Definition: SDL_dynapi_overrides.h:387
_this
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
SDL_VideoDevice::num_displays
int num_displays
Definition: SDL_sysvideo.h:323
SDL_windowsvideo.h
SDL_DisplayData::MonitorHandle
HMONITOR MonitorHandle
Definition: SDL_windowsmodes.h:29
SDL_Log
#define SDL_Log
Definition: SDL_dynapi_overrides.h:31
SDL_Rect::y
int y
Definition: SDL_rect.h:79
SDL_Rect::h
int h
Definition: SDL_rect.h:80
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
f
GLfloat f
Definition: SDL_opengl_glext.h:1873
rect
SDL_Rect rect
Definition: testrelative.c:27
_THIS
#define _THIS
Definition: SDL_alsa_audio.h:31
WIN_GetDisplayDPI
int WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay *display, float *ddpi, float *hdpi, float *vdpi)
callback_data
Definition: testmultiaudio.c:25
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
WIN_QuitModes
void WIN_QuitModes(_THIS)
WIN_SetDisplayMode
int WIN_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
SDL_AddVideoDisplay
int SDL_AddVideoDisplay(const SDL_VideoDisplay *display)
Definition: SDL_video.c:606
SDL_VideoDisplay::driverdata
void * driverdata
Definition: SDL_sysvideo.h:140
SDL_DisplayData
Definition: SDL_cocoamodes.h:27
SDL_VideoDevice
Definition: SDL_sysvideo.h:150
SDL_PIXELFORMAT_RGB555
@ SDL_PIXELFORMAT_RGB555
Definition: SDL_pixels.h:197
WIN_GetDisplayBounds
int WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)
SDL_PIXELFORMAT_INDEX4LSB
@ SDL_PIXELFORMAT_INDEX4LSB
Definition: SDL_pixels.h:180
SDL_VideoDisplay
Definition: SDL_sysvideo.h:127
S_OK
#define S_OK
Definition: SDL_directx.h:47
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_Rect
A rectangle, with the origin at the upper left (integer).
Definition: SDL_rect.h:78
SDL_PIXELFORMAT_RGB24
@ SDL_PIXELFORMAT_RGB24
Definition: SDL_pixels.h:233
SDL_PIXELFORMAT_UNKNOWN
@ SDL_PIXELFORMAT_UNKNOWN
Definition: SDL_pixels.h:173
WIN_StringToUTF8
#define WIN_StringToUTF8(S)
Definition: SDL_windows.h:46
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:162
SDL_ComputeDiagonalDPI
float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches)
Definition: SDL_video.c:4046
SDL_DisplayMode::driverdata
void * driverdata
Definition: SDL_video.h:59
SDL_PIXELFORMAT_INDEX8
@ SDL_PIXELFORMAT_INDEX8
Definition: SDL_pixels.h:186
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
SDL_VideoDisplay::current_mode
SDL_DisplayMode current_mode
Definition: SDL_sysvideo.h:133
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:374
SDL_DisplayModeData
Definition: SDL_cocoamodes.h:32
BI_BITFIELDS
#define BI_BITFIELDS
Definition: SDL_bmp.c:48
device
static SDL_AudioDeviceID device
Definition: loopwave.c:37
SDL_DisplayModeData::DeviceMode
DEVMODE DeviceMode
Definition: SDL_windowsmodes.h:34
i
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
SDL_VideoData
Definition: SDL_androidvideo.h:37