Mac and Linux SDL2 binary snapshots
Edward Rudd
2018-08-19 561f0d614098a95527367cc3f911e476f35643d6
source/src/video/windows/SDL_windowsmodes.c
@@ -1,6 +1,6 @@
/*
  Simple DirectMedia Layer
  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
@@ -24,56 +24,18 @@
#include "SDL_windowsvideo.h"
#include "../../../include/SDL_assert.h"
#include "../../../include/SDL_log.h"
/* Windows CE compatibility */
#ifndef CDS_FULLSCREEN
#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;
}
/* #define DEBUG_MODES */
static void
WIN_UpdateDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode)
{
    SDL_VideoData *vid_data = (SDL_VideoData *) _this->driverdata;
    SDL_DisplayModeData *data = (SDL_DisplayModeData *) mode->driverdata;
    HDC hdc;
@@ -89,39 +51,8 @@
        int logical_width = GetDeviceCaps( hdc, HORZRES );
        int logical_height = GetDeviceCaps( hdc, VERTRES );
        data->ScaleX = (float)logical_width / data->DeviceMode.dmPelsWidth;
        data->ScaleY = (float)logical_height / data->DeviceMode.dmPelsHeight;
        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;
            RECT monitor_rect;
            dpi_data.vid_data = vid_data;
            dpi_data.mode = mode;
            dpi_data.mode_data = data;
            monitor_rect.left = data->DeviceMode.dmPosition.x;
            monitor_rect.top = data->DeviceMode.dmPosition.y;
            monitor_rect.right = monitor_rect.left + 1;
            monitor_rect.bottom = monitor_rect.top + 1;
            EnumDisplayMonitors(NULL, &monitor_rect, 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;
@@ -199,13 +130,6 @@
    mode->driverdata = data;
    data->DeviceMode = devmode;
    /* Default basic information */
    data->ScaleX = 1.0f;
    data->ScaleY = 1.0f;
    data->DiagDPI = 0.0f;
    data->HorzDPI = 0.0f;
    data->VertDPI = 0.0f;
    mode->format = SDL_PIXELFORMAT_UNKNOWN;
    mode->w = data->DeviceMode.dmPelsWidth;
    mode->h = data->DeviceMode.dmPelsHeight;
@@ -217,7 +141,7 @@
}
static SDL_bool
WIN_AddDisplay(_THIS, LPTSTR DeviceName)
WIN_AddDisplay(_THIS, HMONITOR hMonitor, const MONITORINFOEX *info)
{
    SDL_VideoDisplay display;
    SDL_DisplayData *displaydata;
@@ -225,9 +149,10 @@
    DISPLAY_DEVICE device;
#ifdef DEBUG_MODES
    printf("Display: %s\n", WIN_StringToUTF8(DeviceName));
    SDL_Log("Display: %s\n", WIN_StringToUTF8(info->szDevice));
#endif
    if (!WIN_GetDisplayMode(_this, DeviceName, ENUM_CURRENT_SETTINGS, &mode)) {
    if (!WIN_GetDisplayMode(_this, info->szDevice, ENUM_CURRENT_SETTINGS, &mode)) {
        return SDL_FALSE;
    }
@@ -235,12 +160,13 @@
    if (!displaydata) {
        return SDL_FALSE;
    }
    SDL_memcpy(displaydata->DeviceName, DeviceName,
    SDL_memcpy(displaydata->DeviceName, info->szDevice,
               sizeof(displaydata->DeviceName));
    displaydata->MonitorHandle = hMonitor;
    SDL_zero(display);
    device.cb = sizeof(device);
    if (EnumDisplayDevices(DeviceName, 0, &device, 0)) {
    if (EnumDisplayDevices(info->szDevice, 0, &device, 0)) {
        display.name = WIN_StringToUTF8(device.DeviceString);
    }
    display.desktop_mode = mode;
@@ -251,63 +177,53 @@
    return SDL_TRUE;
}
typedef struct _WIN_AddDisplaysData {
    SDL_VideoDevice *video_device;
    SDL_bool want_primary;
} WIN_AddDisplaysData;
static BOOL CALLBACK
WIN_AddDisplaysCallback(HMONITOR hMonitor,
                        HDC      hdcMonitor,
                        LPRECT   lprcMonitor,
                        LPARAM   dwData)
{
    WIN_AddDisplaysData *data = (WIN_AddDisplaysData*)dwData;
    MONITORINFOEX info;
    SDL_zero(info);
    info.cbSize = sizeof(info);
    if (GetMonitorInfo(hMonitor, (LPMONITORINFO)&info) != 0) {
        const SDL_bool is_primary = ((info.dwFlags & MONITORINFOF_PRIMARY) == MONITORINFOF_PRIMARY);
        if (is_primary == data->want_primary) {
            WIN_AddDisplay(data->video_device, hMonitor, &info);
        }
    }
    // continue enumeration
    return TRUE;
}
static void
WIN_AddDisplays(_THIS)
{
    WIN_AddDisplaysData callback_data;
    callback_data.video_device = _this;
    callback_data.want_primary = SDL_TRUE;
    EnumDisplayMonitors(NULL, NULL, WIN_AddDisplaysCallback, (LPARAM)&callback_data);
    callback_data.want_primary = SDL_FALSE;
    EnumDisplayMonitors(NULL, NULL, WIN_AddDisplaysCallback, (LPARAM)&callback_data);
}
int
WIN_InitModes(_THIS)
{
    int pass;
    DWORD i, j, count;
    DISPLAY_DEVICE device;
    WIN_AddDisplays(_this);
    device.cb = sizeof(device);
    /* Get the primary display in the first pass */
    for (pass = 0; pass < 2; ++pass) {
        for (i = 0; ; ++i) {
            TCHAR DeviceName[32];
            if (!EnumDisplayDevices(NULL, i, &device, 0)) {
                break;
            }
            if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) {
                continue;
            }
            if (pass == 0) {
                if (!(device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) {
                    continue;
                }
            } else {
                if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
                    continue;
                }
            }
            SDL_memcpy(DeviceName, device.DeviceName, sizeof(DeviceName));
#ifdef DEBUG_MODES
            printf("Device: %s\n", WIN_StringToUTF8(DeviceName));
#endif
            count = 0;
            for (j = 0; ; ++j) {
                if (!EnumDisplayDevices(DeviceName, j, &device, 0)) {
                    break;
                }
                if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) {
                    continue;
                }
                if (pass == 0) {
                    if (!(device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) {
                        continue;
                    }
                } else {
                    if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
                        continue;
                    }
                }
                count += WIN_AddDisplay(_this, device.DeviceName);
            }
            if (count == 0) {
                WIN_AddDisplay(_this, DeviceName);
            }
        }
    }
    if (_this->num_displays == 0) {
        return SDL_SetError("No displays available");
    }
@@ -317,67 +233,104 @@
int
WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
{
    SDL_DisplayModeData *data = (SDL_DisplayModeData *) display->current_mode.driverdata;
    rect->x = (int)SDL_ceil(data->DeviceMode.dmPosition.x * data->ScaleX);
    rect->y = (int)SDL_ceil(data->DeviceMode.dmPosition.y * data->ScaleY);
    rect->w = (int)SDL_ceil(data->DeviceMode.dmPelsWidth * data->ScaleX);
    rect->h = (int)SDL_ceil(data->DeviceMode.dmPelsHeight * data->ScaleY);
    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 : SDL_SetError("Couldn't get DPI");
}
int
WIN_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
{
    const SDL_DisplayModeData *data = (const SDL_DisplayModeData *) display->current_mode.driverdata;
    const DEVMODE *pDevMode = &data->DeviceMode;
    POINT pt = {
        /* !!! FIXME: no scale, right? */
        (LONG) (pDevMode->dmPosition.x + (pDevMode->dmPelsWidth / 2)),
        (LONG) (pDevMode->dmPosition.y + (pDevMode->dmPelsHeight / 2))
    };
    HMONITOR hmon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
    const SDL_DisplayData *data = (const SDL_DisplayData *)display->driverdata;
    MONITORINFO minfo;
    const RECT *work;
    BOOL rc = FALSE;
    BOOL rc;
    SDL_assert(hmon != NULL);
    if (hmon != NULL) {
        SDL_zero(minfo);
        minfo.cbSize = sizeof (MONITORINFO);
        rc = GetMonitorInfo(hmon, &minfo);
        SDL_assert(rc);
    }
    SDL_zero(minfo);
    minfo.cbSize = sizeof(MONITORINFO);
    rc = GetMonitorInfo(data->MonitorHandle, &minfo);
    if (!rc) {
        return SDL_SetError("Couldn't find monitor data");
    }
    work = &minfo.rcWork;
    rect->x = (int)SDL_ceil(work->left * data->ScaleX);
    rect->y = (int)SDL_ceil(work->top * data->ScaleY);
    rect->w = (int)SDL_ceil((work->right - work->left) * data->ScaleX);
    rect->h = (int)SDL_ceil((work->bottom - work->top) * data->ScaleY);
    rect->x = minfo.rcMonitor.left;
    rect->y = minfo.rcMonitor.top;
    rect->w = minfo.rcMonitor.right - minfo.rcMonitor.left;
    rect->h = minfo.rcMonitor.bottom - minfo.rcMonitor.top;
    return 0;
}
int
WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi_out, float * hdpi_out, float * vdpi_out)
{
    const SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
    const SDL_VideoData *videodata = (SDL_VideoData *)display->device->driverdata;
    float hdpi = 0, vdpi = 0, ddpi = 0;
    if (videodata->GetDpiForMonitor) {
        UINT hdpi_uint, vdpi_uint;
        // Windows 8.1+ codepath
        if (videodata->GetDpiForMonitor(displaydata->MonitorHandle, MDT_EFFECTIVE_DPI, &hdpi_uint, &vdpi_uint) == S_OK) {
            // GetDpiForMonitor docs promise to return the same hdpi/vdpi
            hdpi = (float)hdpi_uint;
            vdpi = (float)hdpi_uint;
            ddpi = (float)hdpi_uint;
        } else {
            return SDL_SetError("GetDpiForMonitor failed");
        }
    } else {
        // Window 8.0 and below: same DPI for all monitors.
        HDC hdc;
        int hdpi_int, vdpi_int, hpoints, vpoints, hpix, vpix;
        float hinches, vinches;
        hdc = GetDC(NULL);
        if (hdc == NULL) {
            return SDL_SetError("GetDC failed");
        }
        hdpi_int = GetDeviceCaps(hdc, LOGPIXELSX);
        vdpi_int = GetDeviceCaps(hdc, LOGPIXELSY);
        ReleaseDC(NULL, hdc);
        hpoints = GetSystemMetrics(SM_CXVIRTUALSCREEN);
        vpoints = GetSystemMetrics(SM_CYVIRTUALSCREEN);
        hpix = MulDiv(hpoints, hdpi_int, 96);
        vpix = MulDiv(vpoints, vdpi_int, 96);
        hinches = (float)hpoints / 96.0f;
        vinches = (float)vpoints / 96.0f;
        hdpi = (float)hdpi_int;
        vdpi = (float)vdpi_int;
        ddpi = SDL_ComputeDiagonalDPI(hpix, vpix, hinches, vinches);
    }
    if (ddpi_out) {
        *ddpi_out = ddpi;
    }
    if (hdpi_out) {
        *hdpi_out = hdpi;
    }
    if (vdpi_out) {
        *vdpi_out = vdpi;
    }
    return ddpi != 0.0f ? 0 : SDL_SetError("Couldn't get DPI");
}
int
WIN_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
{
    const SDL_DisplayData *data = (const SDL_DisplayData *)display->driverdata;
    MONITORINFO minfo;
    BOOL rc;
    SDL_zero(minfo);
    minfo.cbSize = sizeof(MONITORINFO);
    rc = GetMonitorInfo(data->MonitorHandle, &minfo);
    if (!rc) {
        return SDL_SetError("Couldn't find monitor data");
    }
    rect->x = minfo.rcWork.left;
    rect->y = minfo.rcWork.top;
    rect->w = minfo.rcWork.right - minfo.rcWork.left;
    rect->h = minfo.rcWork.bottom - minfo.rcWork.top;
    return 0;
}