SDL 2.0
SDL_windowsmodes.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 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
36static void
37WIN_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_zero(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:
70 break;
71 case 0x000000FF:
73 break;
74 case 0xF800:
76 break;
77 case 0x7C00:
79 break;
80 }
81 } else if (bmi->bmiHeader.biBitCount == 8) {
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:
92 break;
93 case 24:
95 break;
96 case 16:
98 break;
99 case 15:
101 break;
102 case 8:
104 break;
105 case 4:
107 break;
108 }
109 }
110 }
111}
112
113static SDL_bool
114WIN_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
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
143static SDL_bool
144WIN_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
180typedef struct _WIN_AddDisplaysData {
181 SDL_VideoDevice *video_device;
182 SDL_bool want_primary;
183} WIN_AddDisplaysData;
184
185static BOOL CALLBACK
186WIN_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
209static void
210WIN_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
222int
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
233int
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
256int
257WIN_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
315int
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
338void
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
364int
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
399void
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: */
#define _THIS
#define BI_BITFIELDS
Definition: SDL_bmp.c:48
#define S_OK
Definition: SDL_directx.h:47
#define SDL_SetError
#define SDL_malloc
#define SDL_free
#define SDL_memcpy
#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:194
@ SDL_PIXELFORMAT_INDEX8
Definition: SDL_pixels.h:186
@ SDL_PIXELFORMAT_BGR888
Definition: SDL_pixels.h:242
@ SDL_PIXELFORMAT_RGB24
Definition: SDL_pixels.h:230
@ SDL_PIXELFORMAT_RGB888
Definition: SDL_pixels.h:236
@ SDL_PIXELFORMAT_INDEX4LSB
Definition: SDL_pixels.h:180
@ SDL_PIXELFORMAT_RGB565
Definition: SDL_pixels.h:224
@ SDL_PIXELFORMAT_UNKNOWN
Definition: SDL_pixels.h:173
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
uint32_t Uint32
Definition: SDL_stdinc.h:203
int SDL_AddVideoDisplay(const SDL_VideoDisplay *display)
Definition: SDL_video.c:603
float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches)
Definition: SDL_video.c:4015
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:751
static SDL_VideoDevice * _this
Definition: SDL_video.c:118
#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_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:167
#define TRUE
Definition: edid-parse.c:33
static SDL_AudioDeviceID device
Definition: loopwave.c:37
TCHAR 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_DisplayMode desktop_mode
Definition: SDL_sysvideo.h:131
SDL_VideoDevice * device
Definition: SDL_sysvideo.h:137
SDL_DisplayMode current_mode
Definition: SDL_sysvideo.h:132
SDL_Rect rect
Definition: testrelative.c:27