Add SDL_GetDisplayDPI routine and implement for Windows.
authorAlfred Reynolds <alfred@valvesoftware.com>
Wed, 29 Jul 2015 17:18:56 -0700
changeset 98130652406e46c6
parent 9812 9b4dd9efb04e
child 9814 4df28b087060
Add SDL_GetDisplayDPI routine and implement for Windows.
include/SDL_video.h
src/dynapi/SDL_dynapi_overrides.h
src/dynapi/SDL_dynapi_procs.h
src/video/SDL_sysvideo.h
src/video/SDL_video.c
src/video/windows/SDL_windowsmodes.c
src/video/windows/SDL_windowsmodes.h
src/video/windows/SDL_windowsvideo.c
src/video/windows/SDL_windowsvideo.h
     1.1 --- a/include/SDL_video.h	Tue Jul 28 00:12:50 2015 -0400
     1.2 +++ b/include/SDL_video.h	Wed Jul 29 17:18:56 2015 -0700
     1.3 @@ -297,6 +297,18 @@
     1.4  extern DECLSPEC int SDLCALL SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect);
     1.5  
     1.6  /**
     1.7 + *  \brief Get the dots/pixels-per-inch for a display
     1.8 + *
     1.9 + *  \note Diagonal, horizontal and vertical DPI can all be optionally
    1.10 + *        returned if the parameter is non-NULL.
    1.11 + *
    1.12 + *  \return 0 on success, or -1 if no DPI information is available or the index is out of range.
    1.13 + *
    1.14 + *  \sa SDL_GetNumVideoDisplays()
    1.15 + */
    1.16 +extern DECLSPEC int SDLCALL SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi);
    1.17 +
    1.18 +/**
    1.19   *  \brief Returns the number of available display modes.
    1.20   *
    1.21   *  \sa SDL_GetDisplayMode()
     2.1 --- a/src/dynapi/SDL_dynapi_overrides.h	Tue Jul 28 00:12:50 2015 -0400
     2.2 +++ b/src/dynapi/SDL_dynapi_overrides.h	Wed Jul 29 17:18:56 2015 -0700
     2.3 @@ -505,6 +505,7 @@
     2.4  #define SDL_GetNumVideoDisplays SDL_GetNumVideoDisplays_REAL
     2.5  #define SDL_GetDisplayName SDL_GetDisplayName_REAL
     2.6  #define SDL_GetDisplayBounds SDL_GetDisplayBounds_REAL
     2.7 +#define SDL_GetDisplayDPI SDL_GetDisplayDPI_REAL
     2.8  #define SDL_GetNumDisplayModes SDL_GetNumDisplayModes_REAL
     2.9  #define SDL_GetDisplayMode SDL_GetDisplayMode_REAL
    2.10  #define SDL_GetDesktopDisplayMode SDL_GetDesktopDisplayMode_REAL
     3.1 --- a/src/dynapi/SDL_dynapi_procs.h	Tue Jul 28 00:12:50 2015 -0400
     3.2 +++ b/src/dynapi/SDL_dynapi_procs.h	Wed Jul 29 17:18:56 2015 -0700
     3.3 @@ -534,6 +534,7 @@
     3.4  SDL_DYNAPI_PROC(int,SDL_GetNumVideoDisplays,(void),(),return)
     3.5  SDL_DYNAPI_PROC(const char*,SDL_GetDisplayName,(int a),(a),return)
     3.6  SDL_DYNAPI_PROC(int,SDL_GetDisplayBounds,(int a, SDL_Rect *b),(a,b),return)
     3.7 +SDL_DYNAPI_PROC(int,SDL_GetDisplayDPI,(int a, float *b, float *c, float *d),(a,b,c,d),return)
     3.8  SDL_DYNAPI_PROC(int,SDL_GetNumDisplayModes,(int a),(a),return)
     3.9  SDL_DYNAPI_PROC(int,SDL_GetDisplayMode,(int a, int b, SDL_DisplayMode *c),(a,b,c),return)
    3.10  SDL_DYNAPI_PROC(int,SDL_GetDesktopDisplayMode,(int a, SDL_DisplayMode *b),(a,b),return)
     4.1 --- a/src/video/SDL_sysvideo.h	Tue Jul 28 00:12:50 2015 -0400
     4.2 +++ b/src/video/SDL_sysvideo.h	Wed Jul 29 17:18:56 2015 -0700
     4.3 @@ -171,6 +171,11 @@
     4.4      int (*GetDisplayBounds) (_THIS, SDL_VideoDisplay * display, SDL_Rect * rect);
     4.5  
     4.6      /*
     4.7 +     * Get the dots/pixels-per-inch of a display
     4.8 +     */
     4.9 +    int (*GetDisplayDPI) (_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi);
    4.10 +
    4.11 +    /*
    4.12       * Get a list of the available display modes for a display.
    4.13       */
    4.14      void (*GetDisplayModes) (_THIS, SDL_VideoDisplay * display);
    4.15 @@ -423,6 +428,8 @@
    4.16  
    4.17  extern SDL_bool SDL_ShouldAllowTopmost(void);
    4.18  
    4.19 +extern float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches);
    4.20 +
    4.21  #endif /* _SDL_sysvideo_h */
    4.22  
    4.23  /* vi: set ts=4 sw=4 expandtab: */
     5.1 --- a/src/video/SDL_video.c	Tue Jul 28 00:12:50 2015 -0400
     5.2 +++ b/src/video/SDL_video.c	Wed Jul 29 17:18:56 2015 -0700
     5.3 @@ -687,6 +687,24 @@
     5.4      return 0;
     5.5  }
     5.6  
     5.7 +int
     5.8 +SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi)
     5.9 +{
    5.10 +	SDL_VideoDisplay *display;
    5.11 +
    5.12 +    CHECK_DISPLAY_INDEX(displayIndex, -1);
    5.13 +
    5.14 +    display = &_this->displays[displayIndex];
    5.15 +
    5.16 +	if (_this->GetDisplayDPI) {
    5.17 +		if (_this->GetDisplayDPI(_this, display, ddpi, hdpi, vdpi) == 0) {
    5.18 +			return 0;
    5.19 +		}
    5.20 +	}
    5.21 +
    5.22 +	return -1;
    5.23 +}
    5.24 +
    5.25  SDL_bool
    5.26  SDL_AddDisplayMode(SDL_VideoDisplay * display,  const SDL_DisplayMode * mode)
    5.27  {
    5.28 @@ -3538,4 +3556,15 @@
    5.29      return 0;
    5.30  }
    5.31  
    5.32 +float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches)
    5.33 +{
    5.34 +	float den2 = hinches * hinches + vinches * vinches;
    5.35 +	if ( den2 <= 0.0f ) {
    5.36 +		return 0.0f;
    5.37 +	}
    5.38 +		
    5.39 +	return (float)(SDL_sqrt((double)hpix * (double)hpix + (double)vpix * (double)vpix) /
    5.40 +				   SDL_sqrt((double)den2));
    5.41 +}
    5.42 +
    5.43  /* vi: set ts=4 sw=4 expandtab: */
     6.1 --- a/src/video/windows/SDL_windowsmodes.c	Tue Jul 28 00:12:50 2015 -0400
     6.2 +++ b/src/video/windows/SDL_windowsmodes.c	Wed Jul 29 17:18:56 2015 -0700
     6.3 @@ -29,9 +29,50 @@
     6.4  #define CDS_FULLSCREEN 0
     6.5  #endif
     6.6  
     6.7 +typedef struct _WIN_GetMonitorDPIData {
     6.8 +	SDL_VideoData *vid_data;
     6.9 +	SDL_DisplayMode *mode;
    6.10 +	SDL_DisplayModeData *mode_data;
    6.11 +} WIN_GetMonitorDPIData;
    6.12 +
    6.13 +static BOOL CALLBACK
    6.14 +WIN_GetMonitorDPI(HMONITOR hMonitor,
    6.15 +				  HDC      hdcMonitor,
    6.16 +				  LPRECT   lprcMonitor,
    6.17 +				  LPARAM   dwData)
    6.18 +{
    6.19 +	WIN_GetMonitorDPIData *data = (WIN_GetMonitorDPIData*) dwData;
    6.20 +	UINT hdpi, vdpi;
    6.21 +
    6.22 +	if (data->vid_data->GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &hdpi, &vdpi) == S_OK &&
    6.23 +		hdpi > 0 &&
    6.24 +		vdpi > 0) {
    6.25 +		float hsize, vsize;
    6.26 +		
    6.27 +		data->mode_data->HorzDPI = (float)hdpi;
    6.28 +		data->mode_data->VertDPI = (float)vdpi;
    6.29 +
    6.30 +		// Figure out the monitor size and compute the diagonal DPI.
    6.31 +		hsize = data->mode->w / data->mode_data->HorzDPI;
    6.32 +		vsize = data->mode->h / data->mode_data->VertDPI;
    6.33 +		
    6.34 +		data->mode_data->DiagDPI = SDL_ComputeDiagonalDPI( data->mode->w,
    6.35 +														   data->mode->h,
    6.36 +														   hsize,
    6.37 +														   vsize );
    6.38 +
    6.39 +		// We can only handle one DPI per display mode so end the enumeration.
    6.40 +		return FALSE;
    6.41 +	}
    6.42 +
    6.43 +	// We didn't get DPI information so keep going.
    6.44 +	return TRUE;
    6.45 +}
    6.46 +
    6.47  static SDL_bool
    6.48 -WIN_GetDisplayMode(LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode)
    6.49 +WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode)
    6.50  {
    6.51 +    SDL_VideoData *vid_data = (SDL_VideoData *) _this->driverdata;
    6.52      SDL_DisplayModeData *data;
    6.53      DEVMODE devmode;
    6.54      HDC hdc;
    6.55 @@ -52,6 +93,9 @@
    6.56           DM_DISPLAYFLAGS);
    6.57  	data->ScaleX = 1.0f;
    6.58  	data->ScaleY = 1.0f;
    6.59 +	data->DiagDPI = 0.0f;
    6.60 +	data->HorzDPI = 0.0f;
    6.61 +	data->VertDPI = 0.0f;
    6.62  
    6.63      /* Fill in the mode information */
    6.64      mode->format = SDL_PIXELFORMAT_UNKNOWN;
    6.65 @@ -73,6 +117,30 @@
    6.66  		mode->w = logical_width;
    6.67  		mode->h = logical_height;
    6.68  
    6.69 +		// WIN_GetMonitorDPI needs mode->w and mode->h
    6.70 +		// so only call after those are set.
    6.71 +		if (vid_data->GetDpiForMonitor) {
    6.72 +			WIN_GetMonitorDPIData dpi_data;
    6.73 +
    6.74 +			dpi_data.vid_data = vid_data;
    6.75 +			dpi_data.mode = mode;
    6.76 +			dpi_data.mode_data = data;
    6.77 +			EnumDisplayMonitors(hdc, NULL, WIN_GetMonitorDPI, (LPARAM)&dpi_data);
    6.78 +		} else {
    6.79 +			// We don't have the Windows 8.1 routine so just
    6.80 +			// get system DPI.
    6.81 +			data->HorzDPI = (float)GetDeviceCaps( hdc, LOGPIXELSX );
    6.82 +			data->VertDPI = (float)GetDeviceCaps( hdc, LOGPIXELSY );
    6.83 +			if (data->HorzDPI == data->VertDPI) {
    6.84 +				data->DiagDPI = data->HorzDPI;
    6.85 +			} else {
    6.86 +				data->DiagDPI = SDL_ComputeDiagonalDPI( mode->w,
    6.87 +														mode->h,
    6.88 +														(float)GetDeviceCaps( hdc, HORZSIZE ) / 25.4f,
    6.89 +														(float)GetDeviceCaps( hdc, VERTSIZE ) / 25.4f );
    6.90 +			}
    6.91 +		}
    6.92 +		
    6.93          SDL_zero(bmi_data);
    6.94          bmi = (LPBITMAPINFO) bmi_data;
    6.95          bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    6.96 @@ -131,7 +199,7 @@
    6.97  }
    6.98  
    6.99  static SDL_bool
   6.100 -WIN_AddDisplay(LPTSTR DeviceName)
   6.101 +WIN_AddDisplay(_THIS, LPTSTR DeviceName)
   6.102  {
   6.103      SDL_VideoDisplay display;
   6.104      SDL_DisplayData *displaydata;
   6.105 @@ -141,7 +209,7 @@
   6.106  #ifdef DEBUG_MODES
   6.107      printf("Display: %s\n", WIN_StringToUTF8(DeviceName));
   6.108  #endif
   6.109 -    if (!WIN_GetDisplayMode(DeviceName, ENUM_CURRENT_SETTINGS, &mode)) {
   6.110 +    if (!WIN_GetDisplayMode(_this, DeviceName, ENUM_CURRENT_SETTINGS, &mode)) {
   6.111          return SDL_FALSE;
   6.112      }
   6.113  
   6.114 @@ -215,10 +283,10 @@
   6.115                          continue;
   6.116                      }
   6.117                  }
   6.118 -                count += WIN_AddDisplay(device.DeviceName);
   6.119 +                count += WIN_AddDisplay(_this, device.DeviceName);
   6.120              }
   6.121              if (count == 0) {
   6.122 -                WIN_AddDisplay(DeviceName);
   6.123 +                WIN_AddDisplay(_this, DeviceName);
   6.124              }
   6.125          }
   6.126      }
   6.127 @@ -241,6 +309,24 @@
   6.128      return 0;
   6.129  }
   6.130  
   6.131 +int
   6.132 +WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi)
   6.133 +{
   6.134 +    SDL_DisplayModeData *data = (SDL_DisplayModeData *) display->current_mode.driverdata;
   6.135 +
   6.136 +	if (ddpi) {
   6.137 +		*ddpi = data->DiagDPI;
   6.138 +	}
   6.139 +	if (hdpi) {
   6.140 +		*hdpi = data->HorzDPI;
   6.141 +	}
   6.142 +	if (vdpi) {
   6.143 +		*vdpi = data->VertDPI;
   6.144 +	}
   6.145 +
   6.146 +	return data->DiagDPI != 0.0f ? 0 : -1;
   6.147 +}
   6.148 +
   6.149  void
   6.150  WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
   6.151  {
   6.152 @@ -249,7 +335,7 @@
   6.153      SDL_DisplayMode mode;
   6.154  
   6.155      for (i = 0;; ++i) {
   6.156 -        if (!WIN_GetDisplayMode(data->DeviceName, i, &mode)) {
   6.157 +        if (!WIN_GetDisplayMode(_this, data->DeviceName, i, &mode)) {
   6.158              break;
   6.159          }
   6.160          if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
     7.1 --- a/src/video/windows/SDL_windowsmodes.h	Tue Jul 28 00:12:50 2015 -0400
     7.2 +++ b/src/video/windows/SDL_windowsmodes.h	Wed Jul 29 17:18:56 2015 -0700
     7.3 @@ -33,10 +33,14 @@
     7.4      DEVMODE DeviceMode;
     7.5  	float ScaleX;
     7.6  	float ScaleY;
     7.7 +    float DiagDPI;
     7.8 +	float HorzDPI;
     7.9 +	float VertDPI;
    7.10  } SDL_DisplayModeData;
    7.11  
    7.12  extern int WIN_InitModes(_THIS);
    7.13  extern int WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect);
    7.14 +extern int WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi);
    7.15  extern void WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display);
    7.16  extern int WIN_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
    7.17  extern void WIN_QuitModes(_THIS);
     8.1 --- a/src/video/windows/SDL_windowsvideo.c	Tue Jul 28 00:12:50 2015 -0400
     8.2 +++ b/src/video/windows/SDL_windowsvideo.c	Wed Jul 29 17:18:56 2015 -0700
     8.3 @@ -78,6 +78,9 @@
     8.4      if (data->userDLL) {
     8.5          SDL_UnloadObject(data->userDLL);
     8.6      }
     8.7 +    if (data->shcoreDLL) {
     8.8 +        SDL_UnloadObject(data->shcoreDLL);
     8.9 +    }
    8.10  
    8.11      SDL_free(device->driverdata);
    8.12      SDL_free(device);
    8.13 @@ -112,10 +115,16 @@
    8.14          data->RegisterTouchWindow = (BOOL (WINAPI *)(HWND, ULONG)) SDL_LoadFunction(data->userDLL, "RegisterTouchWindow");
    8.15      }
    8.16  
    8.17 +    data->shcoreDLL = SDL_LoadObject("SHCORE.DLL");
    8.18 +    if (data->shcoreDLL) {
    8.19 +        data->GetDpiForMonitor = (HRESULT (WINAPI *)(HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *)) SDL_LoadFunction(data->shcoreDLL, "GetDpiForMonitor");
    8.20 +    }
    8.21 +
    8.22      /* Set the function pointers */
    8.23      device->VideoInit = WIN_VideoInit;
    8.24      device->VideoQuit = WIN_VideoQuit;
    8.25      device->GetDisplayBounds = WIN_GetDisplayBounds;
    8.26 +    device->GetDisplayDPI = WIN_GetDisplayDPI;
    8.27      device->GetDisplayModes = WIN_GetDisplayModes;
    8.28      device->SetDisplayMode = WIN_SetDisplayMode;
    8.29      device->PumpEvents = WIN_PumpEvents;
     9.1 --- a/src/video/windows/SDL_windowsvideo.h	Tue Jul 28 00:12:50 2015 -0400
     9.2 +++ b/src/video/windows/SDL_windowsvideo.h	Wed Jul 29 17:18:56 2015 -0700
     9.3 @@ -76,6 +76,17 @@
     9.4  
     9.5  #endif /* WINVER < 0x0601 */
     9.6  
     9.7 +#if WINVER < 0x0603
     9.8 +
     9.9 +typedef enum MONITOR_DPI_TYPE {
    9.10 +    MDT_EFFECTIVE_DPI = 0,
    9.11 +    MDT_ANGULAR_DPI = 1,
    9.12 +    MDT_RAW_DPI = 2,
    9.13 +    MDT_DEFAULT = MDT_EFFECTIVE_DPI
    9.14 +} MONITOR_DPI_TYPE;
    9.15 +
    9.16 +#endif /* WINVER < 0x0603 */
    9.17 +
    9.18  typedef BOOL  (*PFNSHFullScreen)(HWND, DWORD);
    9.19  typedef void  (*PFCoordTransform)(SDL_Window*, POINT*);
    9.20  
    9.21 @@ -124,6 +135,12 @@
    9.22      BOOL (WINAPI *GetTouchInputInfo)( HTOUCHINPUT, UINT, PTOUCHINPUT, int );
    9.23      BOOL (WINAPI *RegisterTouchWindow)( HWND, ULONG );
    9.24  
    9.25 +    void* shcoreDLL;
    9.26 +    HRESULT (WINAPI *GetDpiForMonitor)( HMONITOR         hmonitor,
    9.27 +                                        MONITOR_DPI_TYPE dpiType,
    9.28 +                                        UINT             *dpiX,
    9.29 +                                        UINT             *dpiY );
    9.30 +    
    9.31      SDL_bool ime_com_initialized;
    9.32      struct ITfThreadMgr *ime_threadmgr;
    9.33      SDL_bool ime_initialized;