src/video/windows/SDL_windowsmodes.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 26 May 2015 06:27:46 -0700
changeset 9619 b94b6d0bff0f
parent 8795 513d97ffe10d
child 9813 0652406e46c6
permissions -rw-r--r--
Updated the copyright year to 2015
slouken@1895
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@9619
     3
  Copyright (C) 1997-2015 Sam Lantinga <slouken@libsdl.org>
slouken@1895
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@1895
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@1895
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@1895
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@1895
    22
slouken@6044
    23
#if SDL_VIDEO_DRIVER_WINDOWS
slouken@6044
    24
slouken@5062
    25
#include "SDL_windowsvideo.h"
slouken@1895
    26
slouken@5086
    27
/* Windows CE compatibility */
slouken@5086
    28
#ifndef CDS_FULLSCREEN
slouken@5086
    29
#define CDS_FULLSCREEN 0
slouken@5086
    30
#endif
slouken@1895
    31
slouken@1895
    32
static SDL_bool
slouken@1895
    33
WIN_GetDisplayMode(LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode)
slouken@1895
    34
{
slouken@1895
    35
    SDL_DisplayModeData *data;
slouken@1895
    36
    DEVMODE devmode;
slouken@1895
    37
    HDC hdc;
slouken@1895
    38
slouken@1895
    39
    devmode.dmSize = sizeof(devmode);
slouken@1895
    40
    devmode.dmDriverExtra = 0;
slouken@1895
    41
    if (!EnumDisplaySettings(deviceName, index, &devmode)) {
slouken@1895
    42
        return SDL_FALSE;
slouken@1895
    43
    }
slouken@1895
    44
slouken@1895
    45
    data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
slouken@1895
    46
    if (!data) {
slouken@1895
    47
        return SDL_FALSE;
slouken@1895
    48
    }
slouken@1895
    49
    data->DeviceMode = devmode;
slouken@1895
    50
    data->DeviceMode.dmFields =
slouken@1895
    51
        (DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY |
slouken@1895
    52
         DM_DISPLAYFLAGS);
slouken@8086
    53
	data->ScaleX = 1.0f;
slouken@8086
    54
	data->ScaleY = 1.0f;
slouken@1895
    55
slouken@1895
    56
    /* Fill in the mode information */
slouken@1965
    57
    mode->format = SDL_PIXELFORMAT_UNKNOWN;
slouken@1895
    58
    mode->w = devmode.dmPelsWidth;
slouken@1895
    59
    mode->h = devmode.dmPelsHeight;
slouken@1895
    60
    mode->refresh_rate = devmode.dmDisplayFrequency;
slouken@1895
    61
    mode->driverdata = data;
slouken@1895
    62
slouken@1913
    63
    if (index == ENUM_CURRENT_SETTINGS
slouken@1913
    64
        && (hdc = CreateDC(deviceName, NULL, NULL, NULL)) != NULL) {
slouken@1895
    65
        char bmi_data[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];
slouken@1895
    66
        LPBITMAPINFO bmi;
slouken@1895
    67
        HBITMAP hbm;
slouken@8086
    68
		int logical_width = GetDeviceCaps( hdc, HORZRES );
slouken@8086
    69
		int logical_height = GetDeviceCaps( hdc, VERTRES );
slouken@8086
    70
slouken@8086
    71
		data->ScaleX = (float)logical_width / devmode.dmPelsWidth;
slouken@8086
    72
		data->ScaleY = (float)logical_height / devmode.dmPelsHeight;
slouken@8086
    73
		mode->w = logical_width;
slouken@8086
    74
		mode->h = logical_height;
slouken@1895
    75
slouken@1895
    76
        SDL_zero(bmi_data);
slouken@1895
    77
        bmi = (LPBITMAPINFO) bmi_data;
slouken@1895
    78
        bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
slouken@1895
    79
slouken@1895
    80
        hbm = CreateCompatibleBitmap(hdc, 1, 1);
slouken@1895
    81
        GetDIBits(hdc, hbm, 0, 1, NULL, bmi, DIB_RGB_COLORS);
slouken@1895
    82
        GetDIBits(hdc, hbm, 0, 1, NULL, bmi, DIB_RGB_COLORS);
slouken@1895
    83
        DeleteObject(hbm);
slouken@1895
    84
        DeleteDC(hdc);
slouken@1895
    85
        if (bmi->bmiHeader.biCompression == BI_BITFIELDS) {
slouken@1895
    86
            switch (*(Uint32 *) bmi->bmiColors) {
slouken@1895
    87
            case 0x00FF0000:
slouken@1965
    88
                mode->format = SDL_PIXELFORMAT_RGB888;
slouken@1895
    89
                break;
slouken@1895
    90
            case 0x000000FF:
slouken@1965
    91
                mode->format = SDL_PIXELFORMAT_BGR888;
slouken@1895
    92
                break;
slouken@1895
    93
            case 0xF800:
slouken@1965
    94
                mode->format = SDL_PIXELFORMAT_RGB565;
slouken@1895
    95
                break;
slouken@1895
    96
            case 0x7C00:
slouken@1965
    97
                mode->format = SDL_PIXELFORMAT_RGB555;
slouken@1895
    98
                break;
slouken@1895
    99
            }
slouken@1895
   100
        } else if (bmi->bmiHeader.biBitCount == 8) {
slouken@1965
   101
            mode->format = SDL_PIXELFORMAT_INDEX8;
lestat@3175
   102
        } else if (bmi->bmiHeader.biBitCount == 4) {
lestat@3175
   103
            mode->format = SDL_PIXELFORMAT_INDEX4LSB;
slouken@1895
   104
        }
slouken@8086
   105
	} else {
slouken@1913
   106
        /* FIXME: Can we tell what this will be? */
slouken@3186
   107
        if ((devmode.dmFields & DM_BITSPERPEL) == DM_BITSPERPEL) {
lestat@3175
   108
            switch (devmode.dmBitsPerPel) {
lestat@3175
   109
            case 32:
lestat@3175
   110
                mode->format = SDL_PIXELFORMAT_RGB888;
lestat@3175
   111
                break;
lestat@3175
   112
            case 24:
lestat@3175
   113
                mode->format = SDL_PIXELFORMAT_RGB24;
lestat@3175
   114
                break;
lestat@3175
   115
            case 16:
lestat@3175
   116
                mode->format = SDL_PIXELFORMAT_RGB565;
lestat@3175
   117
                break;
lestat@3175
   118
            case 15:
lestat@3175
   119
                mode->format = SDL_PIXELFORMAT_RGB555;
lestat@3175
   120
                break;
lestat@3175
   121
            case 8:
lestat@3175
   122
                mode->format = SDL_PIXELFORMAT_INDEX8;
lestat@3175
   123
                break;
lestat@3175
   124
            case 4:
lestat@3175
   125
                mode->format = SDL_PIXELFORMAT_INDEX4LSB;
lestat@3175
   126
                break;
lestat@3175
   127
            }
slouken@3186
   128
        }
slouken@1895
   129
    }
slouken@1895
   130
    return SDL_TRUE;
slouken@1895
   131
}
slouken@1895
   132
slouken@2149
   133
static SDL_bool
slouken@2119
   134
WIN_AddDisplay(LPTSTR DeviceName)
slouken@2119
   135
{
slouken@2119
   136
    SDL_VideoDisplay display;
slouken@2119
   137
    SDL_DisplayData *displaydata;
slouken@2119
   138
    SDL_DisplayMode mode;
slouken@6793
   139
    DISPLAY_DEVICE device;
slouken@2119
   140
slouken@2119
   141
#ifdef DEBUG_MODES
slouken@2119
   142
    printf("Display: %s\n", WIN_StringToUTF8(DeviceName));
slouken@2119
   143
#endif
slouken@2119
   144
    if (!WIN_GetDisplayMode(DeviceName, ENUM_CURRENT_SETTINGS, &mode)) {
slouken@2149
   145
        return SDL_FALSE;
slouken@2119
   146
    }
slouken@2119
   147
slouken@2119
   148
    displaydata = (SDL_DisplayData *) SDL_malloc(sizeof(*displaydata));
slouken@2119
   149
    if (!displaydata) {
slouken@2149
   150
        return SDL_FALSE;
slouken@2119
   151
    }
slouken@2119
   152
    SDL_memcpy(displaydata->DeviceName, DeviceName,
slouken@2119
   153
               sizeof(displaydata->DeviceName));
slouken@2119
   154
slouken@2119
   155
    SDL_zero(display);
slouken@6793
   156
    device.cb = sizeof(device);
slouken@6793
   157
    if (EnumDisplayDevices(DeviceName, 0, &device, 0)) {
slouken@6793
   158
        display.name = WIN_StringToUTF8(device.DeviceString);
slouken@6793
   159
    }
slouken@2119
   160
    display.desktop_mode = mode;
slouken@2119
   161
    display.current_mode = mode;
slouken@2119
   162
    display.driverdata = displaydata;
slouken@2119
   163
    SDL_AddVideoDisplay(&display);
slouken@6793
   164
    SDL_free(display.name);
slouken@2149
   165
    return SDL_TRUE;
slouken@2119
   166
}
slouken@2119
   167
slouken@3521
   168
int
slouken@1895
   169
WIN_InitModes(_THIS)
slouken@1895
   170
{
slouken@5305
   171
    int pass;
slouken@2149
   172
    DWORD i, j, count;
slouken@1895
   173
    DISPLAY_DEVICE device;
slouken@1895
   174
slouken@1895
   175
    device.cb = sizeof(device);
slouken@1895
   176
slouken@5305
   177
    /* Get the primary display in the first pass */
slouken@5305
   178
    for (pass = 0; pass < 2; ++pass) {
slouken@5305
   179
        for (i = 0; ; ++i) {
slouken@5305
   180
            TCHAR DeviceName[32];
slouken@5305
   181
slouken@5305
   182
            if (!EnumDisplayDevices(NULL, i, &device, 0)) {
slouken@1895
   183
                break;
slouken@1895
   184
            }
slouken@1895
   185
            if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) {
slouken@1895
   186
                continue;
slouken@1895
   187
            }
slouken@5305
   188
            if (pass == 0) {
slouken@5305
   189
                if (!(device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) {
slouken@5305
   190
                    continue;
slouken@5305
   191
                }
slouken@5305
   192
            } else {
slouken@5305
   193
                if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
slouken@5305
   194
                    continue;
slouken@5305
   195
                }
slouken@5305
   196
            }
slouken@5305
   197
            SDL_memcpy(DeviceName, device.DeviceName, sizeof(DeviceName));
slouken@5305
   198
#ifdef DEBUG_MODES
slouken@5305
   199
            printf("Device: %s\n", WIN_StringToUTF8(DeviceName));
slouken@5305
   200
#endif
slouken@5305
   201
            count = 0;
slouken@5305
   202
            for (j = 0; ; ++j) {
slouken@5305
   203
                if (!EnumDisplayDevices(DeviceName, j, &device, 0)) {
slouken@5305
   204
                    break;
slouken@5305
   205
                }
slouken@5305
   206
                if (!(device.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) {
slouken@5305
   207
                    continue;
slouken@5305
   208
                }
slouken@5305
   209
                if (pass == 0) {
slouken@5305
   210
                    if (!(device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) {
slouken@5305
   211
                        continue;
slouken@5305
   212
                    }
slouken@5305
   213
                } else {
slouken@5305
   214
                    if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
slouken@5305
   215
                        continue;
slouken@5305
   216
                    }
slouken@5305
   217
                }
slouken@5305
   218
                count += WIN_AddDisplay(device.DeviceName);
slouken@5305
   219
            }
slouken@5305
   220
            if (count == 0) {
slouken@5305
   221
                WIN_AddDisplay(DeviceName);
slouken@5305
   222
            }
slouken@1895
   223
        }
slouken@1895
   224
    }
slouken@3521
   225
    if (_this->num_displays == 0) {
icculus@7037
   226
        return SDL_SetError("No displays available");
slouken@3521
   227
    }
slouken@3521
   228
    return 0;
slouken@1895
   229
}
slouken@1895
   230
slouken@3528
   231
int
slouken@3528
   232
WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
slouken@3528
   233
{
slouken@5305
   234
    SDL_DisplayModeData *data = (SDL_DisplayModeData *) display->current_mode.driverdata;
slouken@3528
   235
slouken@8086
   236
    rect->x = (int)SDL_ceil(data->DeviceMode.dmPosition.x * data->ScaleX);
slouken@8086
   237
    rect->y = (int)SDL_ceil(data->DeviceMode.dmPosition.y * data->ScaleY);
slouken@8086
   238
    rect->w = (int)SDL_ceil(data->DeviceMode.dmPelsWidth * data->ScaleX);
slouken@8086
   239
    rect->h = (int)SDL_ceil(data->DeviceMode.dmPelsHeight * data->ScaleY);
icculus@6430
   240
slouken@3528
   241
    return 0;
slouken@3528
   242
}
slouken@3528
   243
slouken@1895
   244
void
slouken@3500
   245
WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
slouken@1895
   246
{
slouken@3500
   247
    SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
slouken@1895
   248
    DWORD i;
slouken@1895
   249
    SDL_DisplayMode mode;
slouken@1895
   250
slouken@1895
   251
    for (i = 0;; ++i) {
slouken@1895
   252
        if (!WIN_GetDisplayMode(data->DeviceName, i, &mode)) {
slouken@1895
   253
            break;
slouken@1895
   254
        }
slouken@5305
   255
        if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
slouken@5305
   256
            /* We don't support palettized modes now */
gabomdq@7102
   257
            SDL_free(mode.driverdata);
slouken@5305
   258
            continue;
slouken@5305
   259
        }
slouken@3521
   260
        if (mode.format != SDL_PIXELFORMAT_UNKNOWN) {
slouken@3500
   261
            if (!SDL_AddDisplayMode(display, &mode)) {
lestat@3175
   262
                SDL_free(mode.driverdata);
slouken@3186
   263
            }
slouken@8086
   264
        } else {
gabomdq@7102
   265
            SDL_free(mode.driverdata);
gabomdq@7102
   266
        }
slouken@1895
   267
    }
slouken@1895
   268
}
slouken@1895
   269
slouken@1895
   270
int
slouken@3500
   271
WIN_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
slouken@1895
   272
{
slouken@3500
   273
    SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
slouken@1895
   274
    SDL_DisplayModeData *data = (SDL_DisplayModeData *) mode->driverdata;
slouken@1895
   275
    LONG status;
slouken@3139
   276
slouken@8795
   277
    if (mode->driverdata == display->desktop_mode.driverdata) {
slouken@8795
   278
        status = ChangeDisplaySettingsEx(displaydata->DeviceName, NULL, NULL, 0, NULL);
slouken@8795
   279
    } else {
slouken@8795
   280
        status = ChangeDisplaySettingsEx(displaydata->DeviceName, &data->DeviceMode, NULL, CDS_FULLSCREEN, NULL);
slouken@8795
   281
    }
slouken@5305
   282
    if (status != DISP_CHANGE_SUCCESSFUL) {
slouken@1895
   283
        const char *reason = "Unknown reason";
slouken@1895
   284
        switch (status) {
slouken@1895
   285
        case DISP_CHANGE_BADFLAGS:
slouken@1895
   286
            reason = "DISP_CHANGE_BADFLAGS";
slouken@1895
   287
            break;
slouken@1895
   288
        case DISP_CHANGE_BADMODE:
slouken@1895
   289
            reason = "DISP_CHANGE_BADMODE";
slouken@1895
   290
            break;
slouken@1895
   291
        case DISP_CHANGE_BADPARAM:
slouken@1895
   292
            reason = "DISP_CHANGE_BADPARAM";
slouken@1895
   293
            break;
slouken@1895
   294
        case DISP_CHANGE_FAILED:
slouken@1895
   295
            reason = "DISP_CHANGE_FAILED";
slouken@1895
   296
            break;
slouken@1895
   297
        }
icculus@7037
   298
        return SDL_SetError("ChangeDisplaySettingsEx() failed: %s", reason);
slouken@1895
   299
    }
slouken@5305
   300
    EnumDisplaySettings(displaydata->DeviceName, ENUM_CURRENT_SETTINGS, &data->DeviceMode);
slouken@5305
   301
    return 0;
slouken@1895
   302
}
slouken@1895
   303
slouken@1895
   304
void
slouken@1895
   305
WIN_QuitModes(_THIS)
slouken@1895
   306
{
slouken@5305
   307
    /* All fullscreen windows should have restored modes by now */
slouken@1895
   308
}
slouken@1895
   309
slouken@6044
   310
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
slouken@6044
   311
slouken@1895
   312
/* vi: set ts=4 sw=4 expandtab: */