[Commits] SDL: Add SDL_GetDisplayDPI routine and implement for Windows.

libsdl.org revision control commits-owner at libsdl.org
Thu Jul 30 10:02:22 PDT 2015


details:   https://hg.libsdl.org/SDL/rev/0652406e46c6
changeset: 9813:0652406e46c6
user:      Alfred Reynolds <alfred at valvesoftware.com>
date:      Wed Jul 29 17:18:56 2015 -0700
description:
Add SDL_GetDisplayDPI routine and implement for Windows.

diffstat:

 include/SDL_video.h                  |  12 ++++
 src/dynapi/SDL_dynapi_overrides.h    |   1 +
 src/dynapi/SDL_dynapi_procs.h        |   1 +
 src/video/SDL_sysvideo.h             |   7 ++
 src/video/SDL_video.c                |  29 ++++++++++
 src/video/windows/SDL_windowsmodes.c |  98 +++++++++++++++++++++++++++++++++--
 src/video/windows/SDL_windowsmodes.h |   4 +
 src/video/windows/SDL_windowsvideo.c |   9 +++
 src/video/windows/SDL_windowsvideo.h |  17 ++++++
 9 files changed, 172 insertions(+), 6 deletions(-)

diffs (355 lines):

diff -r 9b4dd9efb04e -r 0652406e46c6 include/SDL_video.h
--- a/include/SDL_video.h	Tue Jul 28 00:12:50 2015 -0400
+++ b/include/SDL_video.h	Wed Jul 29 17:18:56 2015 -0700
@@ -297,6 +297,18 @@
 extern DECLSPEC int SDLCALL SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect);
 
 /**
+ *  \brief Get the dots/pixels-per-inch for a display
+ *
+ *  \note Diagonal, horizontal and vertical DPI can all be optionally
+ *        returned if the parameter is non-NULL.
+ *
+ *  \return 0 on success, or -1 if no DPI information is available or the index is out of range.
+ *
+ *  \sa SDL_GetNumVideoDisplays()
+ */
+extern DECLSPEC int SDLCALL SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi);
+
+/**
  *  \brief Returns the number of available display modes.
  *
  *  \sa SDL_GetDisplayMode()
diff -r 9b4dd9efb04e -r 0652406e46c6 src/dynapi/SDL_dynapi_overrides.h
--- a/src/dynapi/SDL_dynapi_overrides.h	Tue Jul 28 00:12:50 2015 -0400
+++ b/src/dynapi/SDL_dynapi_overrides.h	Wed Jul 29 17:18:56 2015 -0700
@@ -505,6 +505,7 @@
 #define SDL_GetNumVideoDisplays SDL_GetNumVideoDisplays_REAL
 #define SDL_GetDisplayName SDL_GetDisplayName_REAL
 #define SDL_GetDisplayBounds SDL_GetDisplayBounds_REAL
+#define SDL_GetDisplayDPI SDL_GetDisplayDPI_REAL
 #define SDL_GetNumDisplayModes SDL_GetNumDisplayModes_REAL
 #define SDL_GetDisplayMode SDL_GetDisplayMode_REAL
 #define SDL_GetDesktopDisplayMode SDL_GetDesktopDisplayMode_REAL
diff -r 9b4dd9efb04e -r 0652406e46c6 src/dynapi/SDL_dynapi_procs.h
--- a/src/dynapi/SDL_dynapi_procs.h	Tue Jul 28 00:12:50 2015 -0400
+++ b/src/dynapi/SDL_dynapi_procs.h	Wed Jul 29 17:18:56 2015 -0700
@@ -534,6 +534,7 @@
 SDL_DYNAPI_PROC(int,SDL_GetNumVideoDisplays,(void),(),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetDisplayName,(int a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetDisplayBounds,(int a, SDL_Rect *b),(a,b),return)
+SDL_DYNAPI_PROC(int,SDL_GetDisplayDPI,(int a, float *b, float *c, float *d),(a,b,c,d),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumDisplayModes,(int a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetDisplayMode,(int a, int b, SDL_DisplayMode *c),(a,b,c),return)
 SDL_DYNAPI_PROC(int,SDL_GetDesktopDisplayMode,(int a, SDL_DisplayMode *b),(a,b),return)
diff -r 9b4dd9efb04e -r 0652406e46c6 src/video/SDL_sysvideo.h
--- a/src/video/SDL_sysvideo.h	Tue Jul 28 00:12:50 2015 -0400
+++ b/src/video/SDL_sysvideo.h	Wed Jul 29 17:18:56 2015 -0700
@@ -171,6 +171,11 @@
     int (*GetDisplayBounds) (_THIS, SDL_VideoDisplay * display, SDL_Rect * rect);
 
     /*
+     * Get the dots/pixels-per-inch of a display
+     */
+    int (*GetDisplayDPI) (_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi);
+
+    /*
      * Get a list of the available display modes for a display.
      */
     void (*GetDisplayModes) (_THIS, SDL_VideoDisplay * display);
@@ -423,6 +428,8 @@
 
 extern SDL_bool SDL_ShouldAllowTopmost(void);
 
+extern float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches);
+
 #endif /* _SDL_sysvideo_h */
 
 /* vi: set ts=4 sw=4 expandtab: */
diff -r 9b4dd9efb04e -r 0652406e46c6 src/video/SDL_video.c
--- a/src/video/SDL_video.c	Tue Jul 28 00:12:50 2015 -0400
+++ b/src/video/SDL_video.c	Wed Jul 29 17:18:56 2015 -0700
@@ -687,6 +687,24 @@
     return 0;
 }
 
+int
+SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi)
+{
+	SDL_VideoDisplay *display;
+
+    CHECK_DISPLAY_INDEX(displayIndex, -1);
+
+    display = &_this->displays[displayIndex];
+
+	if (_this->GetDisplayDPI) {
+		if (_this->GetDisplayDPI(_this, display, ddpi, hdpi, vdpi) == 0) {
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
 SDL_bool
 SDL_AddDisplayMode(SDL_VideoDisplay * display,  const SDL_DisplayMode * mode)
 {
@@ -3538,4 +3556,15 @@
     return 0;
 }
 
+float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches)
+{
+	float den2 = hinches * hinches + vinches * vinches;
+	if ( den2 <= 0.0f ) {
+		return 0.0f;
+	}
+		
+	return (float)(SDL_sqrt((double)hpix * (double)hpix + (double)vpix * (double)vpix) /
+				   SDL_sqrt((double)den2));
+}
+
 /* vi: set ts=4 sw=4 expandtab: */
diff -r 9b4dd9efb04e -r 0652406e46c6 src/video/windows/SDL_windowsmodes.c
--- a/src/video/windows/SDL_windowsmodes.c	Tue Jul 28 00:12:50 2015 -0400
+++ b/src/video/windows/SDL_windowsmodes.c	Wed Jul 29 17:18:56 2015 -0700
@@ -29,9 +29,50 @@
 #define CDS_FULLSCREEN 0
 #endif
 
+typedef struct _WIN_GetMonitorDPIData {
+	SDL_VideoData *vid_data;
+	SDL_DisplayMode *mode;
+	SDL_DisplayModeData *mode_data;
+} WIN_GetMonitorDPIData;
+
+static BOOL CALLBACK
+WIN_GetMonitorDPI(HMONITOR hMonitor,
+				  HDC      hdcMonitor,
+				  LPRECT   lprcMonitor,
+				  LPARAM   dwData)
+{
+	WIN_GetMonitorDPIData *data = (WIN_GetMonitorDPIData*) dwData;
+	UINT hdpi, vdpi;
+
+	if (data->vid_data->GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &hdpi, &vdpi) == S_OK &&
+		hdpi > 0 &&
+		vdpi > 0) {
+		float hsize, vsize;
+		
+		data->mode_data->HorzDPI = (float)hdpi;
+		data->mode_data->VertDPI = (float)vdpi;
+
+		// Figure out the monitor size and compute the diagonal DPI.
+		hsize = data->mode->w / data->mode_data->HorzDPI;
+		vsize = data->mode->h / data->mode_data->VertDPI;
+		
+		data->mode_data->DiagDPI = SDL_ComputeDiagonalDPI( data->mode->w,
+														   data->mode->h,
+														   hsize,
+														   vsize );
+
+		// We can only handle one DPI per display mode so end the enumeration.
+		return FALSE;
+	}
+
+	// We didn't get DPI information so keep going.
+	return TRUE;
+}
+
 static SDL_bool
-WIN_GetDisplayMode(LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode)
+WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode)
 {
+    SDL_VideoData *vid_data = (SDL_VideoData *) _this->driverdata;
     SDL_DisplayModeData *data;
     DEVMODE devmode;
     HDC hdc;
@@ -52,6 +93,9 @@
          DM_DISPLAYFLAGS);
 	data->ScaleX = 1.0f;
 	data->ScaleY = 1.0f;
+	data->DiagDPI = 0.0f;
+	data->HorzDPI = 0.0f;
+	data->VertDPI = 0.0f;
 
     /* Fill in the mode information */
     mode->format = SDL_PIXELFORMAT_UNKNOWN;
@@ -73,6 +117,30 @@
 		mode->w = logical_width;
 		mode->h = logical_height;
 
+		// WIN_GetMonitorDPI needs mode->w and mode->h
+		// so only call after those are set.
+		if (vid_data->GetDpiForMonitor) {
+			WIN_GetMonitorDPIData dpi_data;
+
+			dpi_data.vid_data = vid_data;
+			dpi_data.mode = mode;
+			dpi_data.mode_data = data;
+			EnumDisplayMonitors(hdc, NULL, WIN_GetMonitorDPI, (LPARAM)&dpi_data);
+		} else {
+			// We don't have the Windows 8.1 routine so just
+			// get system DPI.
+			data->HorzDPI = (float)GetDeviceCaps( hdc, LOGPIXELSX );
+			data->VertDPI = (float)GetDeviceCaps( hdc, LOGPIXELSY );
+			if (data->HorzDPI == data->VertDPI) {
+				data->DiagDPI = data->HorzDPI;
+			} else {
+				data->DiagDPI = SDL_ComputeDiagonalDPI( mode->w,
+														mode->h,
+														(float)GetDeviceCaps( hdc, HORZSIZE ) / 25.4f,
+														(float)GetDeviceCaps( hdc, VERTSIZE ) / 25.4f );
+			}
+		}
+		
         SDL_zero(bmi_data);
         bmi = (LPBITMAPINFO) bmi_data;
         bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
@@ -131,7 +199,7 @@
 }
 
 static SDL_bool
-WIN_AddDisplay(LPTSTR DeviceName)
+WIN_AddDisplay(_THIS, LPTSTR DeviceName)
 {
     SDL_VideoDisplay display;
     SDL_DisplayData *displaydata;
@@ -141,7 +209,7 @@
 #ifdef DEBUG_MODES
     printf("Display: %s\n", WIN_StringToUTF8(DeviceName));
 #endif
-    if (!WIN_GetDisplayMode(DeviceName, ENUM_CURRENT_SETTINGS, &mode)) {
+    if (!WIN_GetDisplayMode(_this, DeviceName, ENUM_CURRENT_SETTINGS, &mode)) {
         return SDL_FALSE;
     }
 
@@ -215,10 +283,10 @@
                         continue;
                     }
                 }
-                count += WIN_AddDisplay(device.DeviceName);
+                count += WIN_AddDisplay(_this, device.DeviceName);
             }
             if (count == 0) {
-                WIN_AddDisplay(DeviceName);
+                WIN_AddDisplay(_this, DeviceName);
             }
         }
     }
@@ -241,6 +309,24 @@
     return 0;
 }
 
+int
+WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi)
+{
+    SDL_DisplayModeData *data = (SDL_DisplayModeData *) display->current_mode.driverdata;
+
+	if (ddpi) {
+		*ddpi = data->DiagDPI;
+	}
+	if (hdpi) {
+		*hdpi = data->HorzDPI;
+	}
+	if (vdpi) {
+		*vdpi = data->VertDPI;
+	}
+
+	return data->DiagDPI != 0.0f ? 0 : -1;
+}
+
 void
 WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
 {
@@ -249,7 +335,7 @@
     SDL_DisplayMode mode;
 
     for (i = 0;; ++i) {
-        if (!WIN_GetDisplayMode(data->DeviceName, i, &mode)) {
+        if (!WIN_GetDisplayMode(_this, data->DeviceName, i, &mode)) {
             break;
         }
         if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
diff -r 9b4dd9efb04e -r 0652406e46c6 src/video/windows/SDL_windowsmodes.h
--- a/src/video/windows/SDL_windowsmodes.h	Tue Jul 28 00:12:50 2015 -0400
+++ b/src/video/windows/SDL_windowsmodes.h	Wed Jul 29 17:18:56 2015 -0700
@@ -33,10 +33,14 @@
     DEVMODE DeviceMode;
 	float ScaleX;
 	float ScaleY;
+    float DiagDPI;
+	float HorzDPI;
+	float VertDPI;
 } SDL_DisplayModeData;
 
 extern int WIN_InitModes(_THIS);
 extern int WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect);
+extern int WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi);
 extern void WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display);
 extern int WIN_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
 extern void WIN_QuitModes(_THIS);
diff -r 9b4dd9efb04e -r 0652406e46c6 src/video/windows/SDL_windowsvideo.c
--- a/src/video/windows/SDL_windowsvideo.c	Tue Jul 28 00:12:50 2015 -0400
+++ b/src/video/windows/SDL_windowsvideo.c	Wed Jul 29 17:18:56 2015 -0700
@@ -78,6 +78,9 @@
     if (data->userDLL) {
         SDL_UnloadObject(data->userDLL);
     }
+    if (data->shcoreDLL) {
+        SDL_UnloadObject(data->shcoreDLL);
+    }
 
     SDL_free(device->driverdata);
     SDL_free(device);
@@ -112,10 +115,16 @@
         data->RegisterTouchWindow = (BOOL (WINAPI *)(HWND, ULONG)) SDL_LoadFunction(data->userDLL, "RegisterTouchWindow");
     }
 
+    data->shcoreDLL = SDL_LoadObject("SHCORE.DLL");
+    if (data->shcoreDLL) {
+        data->GetDpiForMonitor = (HRESULT (WINAPI *)(HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *)) SDL_LoadFunction(data->shcoreDLL, "GetDpiForMonitor");
+    }
+
     /* Set the function pointers */
     device->VideoInit = WIN_VideoInit;
     device->VideoQuit = WIN_VideoQuit;
     device->GetDisplayBounds = WIN_GetDisplayBounds;
+    device->GetDisplayDPI = WIN_GetDisplayDPI;
     device->GetDisplayModes = WIN_GetDisplayModes;
     device->SetDisplayMode = WIN_SetDisplayMode;
     device->PumpEvents = WIN_PumpEvents;
diff -r 9b4dd9efb04e -r 0652406e46c6 src/video/windows/SDL_windowsvideo.h
--- a/src/video/windows/SDL_windowsvideo.h	Tue Jul 28 00:12:50 2015 -0400
+++ b/src/video/windows/SDL_windowsvideo.h	Wed Jul 29 17:18:56 2015 -0700
@@ -76,6 +76,17 @@
 
 #endif /* WINVER < 0x0601 */
 
+#if WINVER < 0x0603
+
+typedef enum MONITOR_DPI_TYPE {
+    MDT_EFFECTIVE_DPI = 0,
+    MDT_ANGULAR_DPI = 1,
+    MDT_RAW_DPI = 2,
+    MDT_DEFAULT = MDT_EFFECTIVE_DPI
+} MONITOR_DPI_TYPE;
+
+#endif /* WINVER < 0x0603 */
+
 typedef BOOL  (*PFNSHFullScreen)(HWND, DWORD);
 typedef void  (*PFCoordTransform)(SDL_Window*, POINT*);
 
@@ -124,6 +135,12 @@
     BOOL (WINAPI *GetTouchInputInfo)( HTOUCHINPUT, UINT, PTOUCHINPUT, int );
     BOOL (WINAPI *RegisterTouchWindow)( HWND, ULONG );
 
+    void* shcoreDLL;
+    HRESULT (WINAPI *GetDpiForMonitor)( HMONITOR         hmonitor,
+                                        MONITOR_DPI_TYPE dpiType,
+                                        UINT             *dpiX,
+                                        UINT             *dpiY );
+    
     SDL_bool ime_com_initialized;
     struct ITfThreadMgr *ime_threadmgr;
     SDL_bool ime_initialized;


More information about the commits mailing list