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 
27 /* Windows CE compatibility */
28 #ifndef CDS_FULLSCREEN
29 #define CDS_FULLSCREEN 0
30 #endif
31 
32 /* #define DEBUG_MODES */
33 
34 static void
35 WIN_UpdateDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode)
36 {
38  HDC hdc;
39 
40  data->DeviceMode.dmFields =
41  (DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY |
42  DM_DISPLAYFLAGS);
43 
44  if (index == ENUM_CURRENT_SETTINGS
45  && (hdc = CreateDC(deviceName, NULL, NULL, NULL)) != NULL) {
46  char bmi_data[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];
47  LPBITMAPINFO bmi;
48  HBITMAP hbm;
49  int logical_width = GetDeviceCaps( hdc, HORZRES );
50  int logical_height = GetDeviceCaps( hdc, VERTRES );
51 
52  mode->w = logical_width;
53  mode->h = logical_height;
54 
55  SDL_zeroa(bmi_data);
56  bmi = (LPBITMAPINFO) bmi_data;
57  bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
58 
59  hbm = CreateCompatibleBitmap(hdc, 1, 1);
60  GetDIBits(hdc, hbm, 0, 1, NULL, bmi, DIB_RGB_COLORS);
61  GetDIBits(hdc, hbm, 0, 1, NULL, bmi, DIB_RGB_COLORS);
62  DeleteObject(hbm);
63  DeleteDC(hdc);
64  if (bmi->bmiHeader.biCompression == BI_BITFIELDS) {
65  switch (*(Uint32 *) bmi->bmiColors) {
66  case 0x00FF0000:
67  mode->format = SDL_PIXELFORMAT_RGB888;
68  break;
69  case 0x000000FF:
70  mode->format = SDL_PIXELFORMAT_BGR888;
71  break;
72  case 0xF800:
73  mode->format = SDL_PIXELFORMAT_RGB565;
74  break;
75  case 0x7C00:
76  mode->format = SDL_PIXELFORMAT_RGB555;
77  break;
78  }
79  } else if (bmi->bmiHeader.biBitCount == 8) {
80  mode->format = SDL_PIXELFORMAT_INDEX8;
81  } else if (bmi->bmiHeader.biBitCount == 4) {
83  }
84  } else if (mode->format == SDL_PIXELFORMAT_UNKNOWN) {
85  /* FIXME: Can we tell what this will be? */
86  if ((data->DeviceMode.dmFields & DM_BITSPERPEL) == DM_BITSPERPEL) {
87  switch (data->DeviceMode.dmBitsPerPel) {
88  case 32:
89  mode->format = SDL_PIXELFORMAT_RGB888;
90  break;
91  case 24:
92  mode->format = SDL_PIXELFORMAT_RGB24;
93  break;
94  case 16:
95  mode->format = SDL_PIXELFORMAT_RGB565;
96  break;
97  case 15:
98  mode->format = SDL_PIXELFORMAT_RGB555;
99  break;
100  case 8:
101  mode->format = SDL_PIXELFORMAT_INDEX8;
102  break;
103  case 4:
105  break;
106  }
107  }
108  }
109 }
110 
111 static SDL_bool
112 WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode)
113 {
115  DEVMODE devmode;
116 
117  devmode.dmSize = sizeof(devmode);
118  devmode.dmDriverExtra = 0;
119  if (!EnumDisplaySettings(deviceName, index, &devmode)) {
120  return SDL_FALSE;
121  }
122 
123  data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
124  if (!data) {
125  return SDL_FALSE;
126  }
127 
128  mode->driverdata = data;
129  data->DeviceMode = devmode;
130 
131  mode->format = SDL_PIXELFORMAT_UNKNOWN;
132  mode->w = data->DeviceMode.dmPelsWidth;
133  mode->h = data->DeviceMode.dmPelsHeight;
134  mode->refresh_rate = data->DeviceMode.dmDisplayFrequency;
135 
136  /* Fill in the mode information */
137  WIN_UpdateDisplayMode(_this, deviceName, index, mode);
138  return SDL_TRUE;
139 }
140 
141 static SDL_bool
142 WIN_AddDisplay(_THIS, HMONITOR hMonitor, const MONITORINFOEXW *info, SDL_bool send_event)
143 {
144  int i;
145  SDL_VideoDisplay display;
146  SDL_DisplayData *displaydata;
148  DISPLAY_DEVICE device;
149 
150 #ifdef DEBUG_MODES
151  SDL_Log("Display: %s\n", WIN_StringToUTF8(info->szDevice));
152 #endif
153 
154  if (!WIN_GetDisplayMode(_this, info->szDevice, ENUM_CURRENT_SETTINGS, &mode)) {
155  return SDL_FALSE;
156  }
157 
158  // Prevent adding duplicate displays. Do this after we know the display is
159  // ready to be added to allow any displays that we can't fully query to be
160  // removed
161  for(i = 0; i < _this->num_displays; ++i) {
163  if (SDL_wcscmp(driverdata->DeviceName, info->szDevice) == 0) {
164  driverdata->MonitorHandle = hMonitor;
165  driverdata->IsValid = SDL_TRUE;
166  return SDL_FALSE;
167  }
168  }
169 
170  displaydata = (SDL_DisplayData *) SDL_malloc(sizeof(*displaydata));
171  if (!displaydata) {
172  return SDL_FALSE;
173  }
174  SDL_memcpy(displaydata->DeviceName, info->szDevice,
175  sizeof(displaydata->DeviceName));
176  displaydata->MonitorHandle = hMonitor;
177  displaydata->IsValid = SDL_TRUE;
178 
179  SDL_zero(display);
180  device.cb = sizeof(device);
181  if (EnumDisplayDevices(info->szDevice, 0, &device, 0)) {
182  display.name = WIN_StringToUTF8(device.DeviceString);
183  }
184  display.desktop_mode = mode;
185  display.current_mode = mode;
186  display.driverdata = displaydata;
187  SDL_AddVideoDisplay(&display, send_event);
188  SDL_free(display.name);
189  return SDL_TRUE;
190 }
191 
192 typedef struct _WIN_AddDisplaysData {
193  SDL_VideoDevice *video_device;
194  SDL_bool send_event;
195  SDL_bool want_primary;
196 } WIN_AddDisplaysData;
197 
198 static BOOL CALLBACK
199 WIN_AddDisplaysCallback(HMONITOR hMonitor,
200  HDC hdcMonitor,
201  LPRECT lprcMonitor,
202  LPARAM dwData)
203 {
204  WIN_AddDisplaysData *data = (WIN_AddDisplaysData*)dwData;
205  MONITORINFOEXW info;
206 
207  SDL_zero(info);
208  info.cbSize = sizeof(info);
209 
210  if (GetMonitorInfoW(hMonitor, (LPMONITORINFO)&info) != 0) {
211  const SDL_bool is_primary = ((info.dwFlags & MONITORINFOF_PRIMARY) == MONITORINFOF_PRIMARY);
212 
213  if (is_primary == data->want_primary) {
214  WIN_AddDisplay(data->video_device, hMonitor, &info, data->send_event);
215  }
216  }
217 
218  // continue enumeration
219  return TRUE;
220 }
221 
222 static void
223 WIN_AddDisplays(_THIS, SDL_bool send_event)
224 {
225  WIN_AddDisplaysData callback_data;
226  callback_data.video_device = _this;
227  callback_data.send_event = send_event;
228 
229  callback_data.want_primary = SDL_TRUE;
230  EnumDisplayMonitors(NULL, NULL, WIN_AddDisplaysCallback, (LPARAM)&callback_data);
231 
232  callback_data.want_primary = SDL_FALSE;
233  EnumDisplayMonitors(NULL, NULL, WIN_AddDisplaysCallback, (LPARAM)&callback_data);
234 }
235 
236 int
238 {
239  WIN_AddDisplays(_this, SDL_FALSE);
240 
241  if (_this->num_displays == 0) {
242  return SDL_SetError("No displays available");
243  }
244  return 0;
245 }
246 
247 int
249 {
250  const SDL_DisplayData *data = (const SDL_DisplayData *)display->driverdata;
251  MONITORINFO minfo;
252  BOOL rc;
253 
254  SDL_zero(minfo);
255  minfo.cbSize = sizeof(MONITORINFO);
256  rc = GetMonitorInfo(data->MonitorHandle, &minfo);
257 
258  if (!rc) {
259  return SDL_SetError("Couldn't find monitor data");
260  }
261 
262  rect->x = minfo.rcMonitor.left;
263  rect->y = minfo.rcMonitor.top;
264  rect->w = minfo.rcMonitor.right - minfo.rcMonitor.left;
265  rect->h = minfo.rcMonitor.bottom - minfo.rcMonitor.top;
266 
267  return 0;
268 }
269 
270 int
271 WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi_out, float * hdpi_out, float * vdpi_out)
272 {
273  const SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
274  const SDL_VideoData *videodata = (SDL_VideoData *)display->device->driverdata;
275  float hdpi = 0, vdpi = 0, ddpi = 0;
276 
277  if (videodata->GetDpiForMonitor) {
278  UINT hdpi_uint, vdpi_uint;
279  // Windows 8.1+ codepath
280  if (videodata->GetDpiForMonitor(displaydata->MonitorHandle, MDT_EFFECTIVE_DPI, &hdpi_uint, &vdpi_uint) == S_OK) {
281  // GetDpiForMonitor docs promise to return the same hdpi/vdpi
282  hdpi = (float)hdpi_uint;
283  vdpi = (float)hdpi_uint;
284  ddpi = (float)hdpi_uint;
285  } else {
286  return SDL_SetError("GetDpiForMonitor failed");
287  }
288  } else {
289  // Window 8.0 and below: same DPI for all monitors.
290  HDC hdc;
291  int hdpi_int, vdpi_int, hpoints, vpoints, hpix, vpix;
292  float hinches, vinches;
293 
294  hdc = GetDC(NULL);
295  if (hdc == NULL) {
296  return SDL_SetError("GetDC failed");
297  }
298  hdpi_int = GetDeviceCaps(hdc, LOGPIXELSX);
299  vdpi_int = GetDeviceCaps(hdc, LOGPIXELSY);
300  ReleaseDC(NULL, hdc);
301 
302  hpoints = GetSystemMetrics(SM_CXVIRTUALSCREEN);
303  vpoints = GetSystemMetrics(SM_CYVIRTUALSCREEN);
304 
305  hpix = MulDiv(hpoints, hdpi_int, 96);
306  vpix = MulDiv(vpoints, vdpi_int, 96);
307 
308  hinches = (float)hpoints / 96.0f;
309  vinches = (float)vpoints / 96.0f;
310 
311  hdpi = (float)hdpi_int;
312  vdpi = (float)vdpi_int;
313  ddpi = SDL_ComputeDiagonalDPI(hpix, vpix, hinches, vinches);
314  }
315 
316  if (ddpi_out) {
317  *ddpi_out = ddpi;
318  }
319  if (hdpi_out) {
320  *hdpi_out = hdpi;
321  }
322  if (vdpi_out) {
323  *vdpi_out = vdpi;
324  }
325 
326  return ddpi != 0.0f ? 0 : SDL_SetError("Couldn't get DPI");
327 }
328 
329 int
331 {
332  const SDL_DisplayData *data = (const SDL_DisplayData *)display->driverdata;
333  MONITORINFO minfo;
334  BOOL rc;
335 
336  SDL_zero(minfo);
337  minfo.cbSize = sizeof(MONITORINFO);
338  rc = GetMonitorInfo(data->MonitorHandle, &minfo);
339 
340  if (!rc) {
341  return SDL_SetError("Couldn't find monitor data");
342  }
343 
344  rect->x = minfo.rcWork.left;
345  rect->y = minfo.rcWork.top;
346  rect->w = minfo.rcWork.right - minfo.rcWork.left;
347  rect->h = minfo.rcWork.bottom - minfo.rcWork.top;
348 
349  return 0;
350 }
351 
352 void
354 {
356  DWORD i;
358 
359  for (i = 0;; ++i) {
360  if (!WIN_GetDisplayMode(_this, data->DeviceName, i, &mode)) {
361  break;
362  }
363  if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
364  /* We don't support palettized modes now */
365  SDL_free(mode.driverdata);
366  continue;
367  }
368  if (mode.format != SDL_PIXELFORMAT_UNKNOWN) {
369  if (!SDL_AddDisplayMode(display, &mode)) {
370  SDL_free(mode.driverdata);
371  }
372  } else {
373  SDL_free(mode.driverdata);
374  }
375  }
376 }
377 
378 int
380 {
381  SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
383  LONG status;
384 
385  if (mode->driverdata == display->desktop_mode.driverdata) {
386  status = ChangeDisplaySettingsEx(displaydata->DeviceName, NULL, NULL, CDS_FULLSCREEN, NULL);
387  } else {
388  status = ChangeDisplaySettingsEx(displaydata->DeviceName, &data->DeviceMode, NULL, CDS_FULLSCREEN, NULL);
389  }
390  if (status != DISP_CHANGE_SUCCESSFUL) {
391  const char *reason = "Unknown reason";
392  switch (status) {
393  case DISP_CHANGE_BADFLAGS:
394  reason = "DISP_CHANGE_BADFLAGS";
395  break;
396  case DISP_CHANGE_BADMODE:
397  reason = "DISP_CHANGE_BADMODE";
398  break;
399  case DISP_CHANGE_BADPARAM:
400  reason = "DISP_CHANGE_BADPARAM";
401  break;
402  case DISP_CHANGE_FAILED:
403  reason = "DISP_CHANGE_FAILED";
404  break;
405  }
406  return SDL_SetError("ChangeDisplaySettingsEx() failed: %s", reason);
407  }
408  EnumDisplaySettings(displaydata->DeviceName, ENUM_CURRENT_SETTINGS, &data->DeviceMode);
409  WIN_UpdateDisplayMode(_this, displaydata->DeviceName, ENUM_CURRENT_SETTINGS, mode);
410  return 0;
411 }
412 
413 void
415 {
416  int i;
417 
418  // Mark all displays as potentially invalid to detect
419  // entries that have actually been removed
420  for (i = 0; i < _this->num_displays; ++i) {
422  driverdata->IsValid = SDL_FALSE;
423  }
424 
425  // Enumerate displays to add any new ones and mark still
426  // connected entries as valid
427  WIN_AddDisplays(_this, SDL_TRUE);
428 
429  // Delete any entries still marked as invalid, iterate
430  // in reverse as each delete takes effect immediately
431  for (i = _this->num_displays - 1; i >= 0; --i) {
433  if (driverdata->IsValid == SDL_FALSE) {
435  }
436  }
437 }
438 
439 void
441 {
442  /* All fullscreen windows should have restored modes by now */
443 }
444 
445 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
446 
447 /* vi: set ts=4 sw=4 expandtab: */
#define _THIS
#define BI_BITFIELDS
Definition: SDL_bmp.c:47
#define S_OK
Definition: SDL_directx.h:47
#define SDL_SetError
#define SDL_malloc
#define SDL_free
#define SDL_memcpy
#define SDL_wcscmp
#define SDL_Log
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLenum mode
GLuint index
#define SDL_ISPIXELFORMAT_INDEXED(format)
Definition: SDL_pixels.h:134
@ SDL_PIXELFORMAT_RGB555
Definition: SDL_pixels.h:202
@ SDL_PIXELFORMAT_INDEX8
Definition: SDL_pixels.h:186
@ SDL_PIXELFORMAT_BGR888
Definition: SDL_pixels.h:253
@ SDL_PIXELFORMAT_RGB24
Definition: SDL_pixels.h:237
@ SDL_PIXELFORMAT_RGB888
Definition: SDL_pixels.h:246
@ SDL_PIXELFORMAT_INDEX4LSB
Definition: SDL_pixels.h:180
@ SDL_PIXELFORMAT_RGB565
Definition: SDL_pixels.h:231
@ SDL_PIXELFORMAT_UNKNOWN
Definition: SDL_pixels.h:173
#define SDL_zero(x)
Definition: SDL_stdinc.h:426
#define SDL_zeroa(x)
Definition: SDL_stdinc.h:428
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
uint32_t Uint32
Definition: SDL_stdinc.h:209
void SDL_DelVideoDisplay(int index)
Definition: SDL_video.c:640
int SDL_AddVideoDisplay(const SDL_VideoDisplay *display, SDL_bool send_event)
Definition: SDL_video.c:607
float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches)
Definition: SDL_video.c:4162
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:792
static SDL_VideoDevice * _this
Definition: SDL_video.c:126
#define WIN_StringToUTF8(S)
Definition: SDL_windows.h:46
int WIN_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)
void WIN_QuitModes(_THIS)
int WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay *display, float *ddpi, float *hdpi, float *vdpi)
void WIN_RefreshDisplays(_THIS)
void WIN_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
int WIN_InitModes(_THIS)
int WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)
int WIN_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
@ MDT_EFFECTIVE_DPI
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 NULL
Definition: begin_code.h:163
#define TRUE
Definition: edid-parse.c:33
static SDL_AudioDeviceID device
Definition: loopwave.c:37
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
WCHAR DeviceName[32]
HMONITOR MonitorHandle
The structure that defines a display mode.
Definition: SDL_video.h:54
void * driverdata
Definition: SDL_video.h:59
A rectangle, with the origin at the upper left (integer).
Definition: SDL_rect.h:78
int h
Definition: SDL_rect.h:80
int w
Definition: SDL_rect.h:80
int y
Definition: SDL_rect.h:79
int x
Definition: SDL_rect.h:79
SDL_VideoDisplay * displays
Definition: SDL_sysvideo.h:326
SDL_DisplayMode desktop_mode
Definition: SDL_sysvideo.h:132
SDL_VideoDevice * device
Definition: SDL_sysvideo.h:138
SDL_DisplayMode current_mode
Definition: SDL_sysvideo.h:133
SDL_Rect rect
Definition: testrelative.c:27