Merge commit 'dec0d4ec4153bf9fc2b78ae6c2df45b6ea8dde7a' as 'external/sdl/SDL'

This commit is contained in:
2023-07-25 22:27:55 +02:00
1663 changed files with 627495 additions and 0 deletions

View File

@ -0,0 +1,246 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_msctf_h_
#define SDL_msctf_h_
#include <unknwn.h>
#define TF_INVALID_COOKIE (0xffffffff)
#define TF_IPSINK_FLAG_ACTIVE 0x0001
#define TF_TMAE_UIELEMENTENABLEDONLY 0x00000004
/* *INDENT-OFF* */ /* clang-format off */
typedef struct ITfThreadMgr ITfThreadMgr;
typedef struct ITfDocumentMgr ITfDocumentMgr;
typedef struct ITfClientId ITfClientId;
typedef struct IEnumTfDocumentMgrs IEnumTfDocumentMgrs;
typedef struct IEnumTfFunctionProviders IEnumTfFunctionProviders;
typedef struct ITfFunctionProvider ITfFunctionProvider;
typedef struct ITfCompartmentMgr ITfCompartmentMgr;
typedef struct ITfContext ITfContext;
typedef struct IEnumTfContexts IEnumTfContexts;
typedef struct ITfUIElementSink ITfUIElementSink;
typedef struct ITfUIElement ITfUIElement;
typedef struct ITfUIElementMgr ITfUIElementMgr;
typedef struct IEnumTfUIElements IEnumTfUIElements;
typedef struct ITfThreadMgrEx ITfThreadMgrEx;
typedef struct ITfCandidateListUIElement ITfCandidateListUIElement;
typedef struct ITfReadingInformationUIElement ITfReadingInformationUIElement;
typedef struct ITfInputProcessorProfileActivationSink ITfInputProcessorProfileActivationSink;
typedef struct ITfSource ITfSource;
typedef DWORD TfClientId;
typedef DWORD TfEditCookie;
typedef struct ITfThreadMgrVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(ITfThreadMgr *, REFIID, void **);
ULONG (STDMETHODCALLTYPE *AddRef)(ITfThreadMgr *);
ULONG (STDMETHODCALLTYPE *Release)(ITfThreadMgr *);
HRESULT (STDMETHODCALLTYPE *Activate)(ITfThreadMgr *, TfClientId *);
HRESULT (STDMETHODCALLTYPE *Deactivate)(ITfThreadMgr *);
HRESULT (STDMETHODCALLTYPE *CreateDocumentMgr)(ITfThreadMgr *);
HRESULT (STDMETHODCALLTYPE *EnumDocumentMgrs)(ITfThreadMgr *, IEnumTfDocumentMgrs **);
HRESULT (STDMETHODCALLTYPE *GetFocus)(ITfThreadMgr *, ITfDocumentMgr **);
HRESULT (STDMETHODCALLTYPE *SetFocus)(ITfThreadMgr *, ITfDocumentMgr *);
HRESULT (STDMETHODCALLTYPE *AssociateFocus)(ITfThreadMgr *, HWND, ITfDocumentMgr *, ITfDocumentMgr **);
HRESULT (STDMETHODCALLTYPE *IsThreadFocus)(ITfThreadMgr *, BOOL *);
HRESULT (STDMETHODCALLTYPE *GetFunctionProvider)(ITfThreadMgr *, REFCLSID, ITfFunctionProvider **);
HRESULT (STDMETHODCALLTYPE *EnumFunctionProviders)(ITfThreadMgr *, IEnumTfFunctionProviders **);
HRESULT (STDMETHODCALLTYPE *GetGlobalCompartment)(ITfThreadMgr *, ITfCompartmentMgr **);
} ITfThreadMgrVtbl;
struct ITfThreadMgr
{
const struct ITfThreadMgrVtbl *lpVtbl;
};
typedef struct ITfThreadMgrExVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(ITfThreadMgrEx *, REFIID, void **);
ULONG (STDMETHODCALLTYPE *AddRef)(ITfThreadMgrEx *);
ULONG (STDMETHODCALLTYPE *Release)(ITfThreadMgrEx *);
HRESULT (STDMETHODCALLTYPE *Activate)(ITfThreadMgrEx *, TfClientId *);
HRESULT (STDMETHODCALLTYPE *Deactivate)(ITfThreadMgrEx *);
HRESULT (STDMETHODCALLTYPE *CreateDocumentMgr)(ITfThreadMgrEx *, ITfDocumentMgr **);
HRESULT (STDMETHODCALLTYPE *EnumDocumentMgrs)(ITfThreadMgrEx *, IEnumTfDocumentMgrs **);
HRESULT (STDMETHODCALLTYPE *GetFocus)(ITfThreadMgrEx *, ITfDocumentMgr **);
HRESULT (STDMETHODCALLTYPE *SetFocus)(ITfThreadMgrEx *, ITfDocumentMgr *);
HRESULT (STDMETHODCALLTYPE *AssociateFocus)(ITfThreadMgrEx *, ITfDocumentMgr *, ITfDocumentMgr **);
HRESULT (STDMETHODCALLTYPE *IsThreadFocus)(ITfThreadMgrEx *, BOOL *);
HRESULT (STDMETHODCALLTYPE *GetFunctionProvider)(ITfThreadMgrEx *, REFCLSID, ITfFunctionProvider **);
HRESULT (STDMETHODCALLTYPE *EnumFunctionProviders)(ITfThreadMgrEx *, IEnumTfFunctionProviders **);
HRESULT (STDMETHODCALLTYPE *GetGlobalCompartment)(ITfThreadMgrEx *, ITfCompartmentMgr **);
HRESULT (STDMETHODCALLTYPE *ActivateEx)(ITfThreadMgrEx *, TfClientId *, DWORD);
HRESULT (STDMETHODCALLTYPE *GetActiveFlags)(ITfThreadMgrEx *, DWORD *);
} ITfThreadMgrExVtbl;
struct ITfThreadMgrEx
{
const struct ITfThreadMgrExVtbl *lpVtbl;
};
typedef struct ITfDocumentMgrVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(ITfDocumentMgr *, REFIID, void **);
ULONG (STDMETHODCALLTYPE *AddRef)(ITfDocumentMgr *);
ULONG (STDMETHODCALLTYPE *Release)(ITfDocumentMgr *);
HRESULT (STDMETHODCALLTYPE *CreateContext)(ITfDocumentMgr *, TfClientId, DWORD, IUnknown *, ITfContext **, TfEditCookie *);
HRESULT (STDMETHODCALLTYPE *Push)(ITfDocumentMgr *, ITfContext *);
HRESULT (STDMETHODCALLTYPE *Pop)(ITfDocumentMgr *);
HRESULT (STDMETHODCALLTYPE *GetTop)(ITfDocumentMgr *, ITfContext **);
HRESULT (STDMETHODCALLTYPE *GetBase)(ITfDocumentMgr *, ITfContext **);
HRESULT (STDMETHODCALLTYPE *EnumContexts)(ITfDocumentMgr *, IEnumTfContexts **);
} ITfDocumentMgrVtbl;
struct ITfDocumentMgr
{
const struct ITfDocumentMgrVtbl *lpVtbl;
};
typedef struct ITfUIElementSinkVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(ITfUIElementSink *, REFIID, void **);
ULONG (STDMETHODCALLTYPE *AddRef)(ITfUIElementSink *);
ULONG (STDMETHODCALLTYPE *Release)(ITfUIElementSink *);
HRESULT (STDMETHODCALLTYPE *BeginUIElement)(ITfUIElementSink *, DWORD, BOOL *);
HRESULT (STDMETHODCALLTYPE *UpdateUIElement)(ITfUIElementSink *, DWORD);
HRESULT (STDMETHODCALLTYPE *EndUIElement)(ITfUIElementSink *, DWORD);
} ITfUIElementSinkVtbl;
struct ITfUIElementSink
{
const struct ITfUIElementSinkVtbl *lpVtbl;
};
typedef struct ITfUIElementMgrVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(ITfUIElementMgr *, REFIID, void **);
ULONG (STDMETHODCALLTYPE *AddRef)(ITfUIElementMgr *);
ULONG (STDMETHODCALLTYPE *Release)(ITfUIElementMgr *);
HRESULT (STDMETHODCALLTYPE *BeginUIElement)(ITfUIElementMgr *, ITfUIElement *, BOOL *, DWORD *);
HRESULT (STDMETHODCALLTYPE *UpdateUIElement)(ITfUIElementMgr *, DWORD);
HRESULT (STDMETHODCALLTYPE *EndUIElement)(ITfUIElementMgr *, DWORD);
HRESULT (STDMETHODCALLTYPE *GetUIElement)(ITfUIElementMgr *, DWORD, ITfUIElement **);
HRESULT (STDMETHODCALLTYPE *EnumUIElements)(ITfUIElementMgr *, IEnumTfUIElements **);
} ITfUIElementMgrVtbl;
struct ITfUIElementMgr
{
const struct ITfUIElementMgrVtbl *lpVtbl;
};
typedef struct ITfCandidateListUIElementVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(ITfCandidateListUIElement *, REFIID, void **);
ULONG (STDMETHODCALLTYPE *AddRef)(ITfCandidateListUIElement *);
ULONG (STDMETHODCALLTYPE *Release)(ITfCandidateListUIElement *);
HRESULT (STDMETHODCALLTYPE *GetDescription)(ITfCandidateListUIElement *, BSTR *);
HRESULT (STDMETHODCALLTYPE *GetGUID)(ITfCandidateListUIElement *, GUID *);
HRESULT (STDMETHODCALLTYPE *Show)(ITfCandidateListUIElement *, BOOL);
HRESULT (STDMETHODCALLTYPE *IsShown)(ITfCandidateListUIElement *, BOOL *);
HRESULT (STDMETHODCALLTYPE *GetUpdatedFlags)(ITfCandidateListUIElement *, DWORD *);
HRESULT (STDMETHODCALLTYPE *GetDocumentMgr)(ITfCandidateListUIElement *, ITfDocumentMgr **);
HRESULT (STDMETHODCALLTYPE *GetCount)(ITfCandidateListUIElement *, UINT *);
HRESULT (STDMETHODCALLTYPE *GetSelection)(ITfCandidateListUIElement *, UINT *);
HRESULT (STDMETHODCALLTYPE *GetString)(ITfCandidateListUIElement *, UINT, BSTR *);
HRESULT (STDMETHODCALLTYPE *GetPageIndex)(ITfCandidateListUIElement *, UINT *, UINT, UINT *);
HRESULT (STDMETHODCALLTYPE *SetPageIndex)(ITfCandidateListUIElement *, UINT *, UINT);
HRESULT (STDMETHODCALLTYPE *GetCurrentPage)(ITfCandidateListUIElement *, UINT *);
} ITfCandidateListUIElementVtbl;
struct ITfCandidateListUIElement
{
const struct ITfCandidateListUIElementVtbl *lpVtbl;
};
typedef struct ITfReadingInformationUIElementVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(ITfReadingInformationUIElement *, REFIID, void **);
ULONG (STDMETHODCALLTYPE *AddRef)(ITfReadingInformationUIElement *);
ULONG (STDMETHODCALLTYPE *Release)(ITfReadingInformationUIElement *);
HRESULT (STDMETHODCALLTYPE *GetDescription)(ITfReadingInformationUIElement *, BSTR *);
HRESULT (STDMETHODCALLTYPE *GetGUID)(ITfReadingInformationUIElement *, GUID *);
HRESULT (STDMETHODCALLTYPE *Show)(ITfReadingInformationUIElement *, BOOL);
HRESULT (STDMETHODCALLTYPE *IsShown)(ITfReadingInformationUIElement *, BOOL *);
HRESULT (STDMETHODCALLTYPE *GetUpdatedFlags)(ITfReadingInformationUIElement *, DWORD *);
HRESULT (STDMETHODCALLTYPE *GetContext)(ITfReadingInformationUIElement *, ITfContext **);
HRESULT (STDMETHODCALLTYPE *GetString)(ITfReadingInformationUIElement *, BSTR *);
HRESULT (STDMETHODCALLTYPE *GetMaxReadingStringLength)(ITfReadingInformationUIElement *, UINT *);
HRESULT (STDMETHODCALLTYPE *GetErrorIndex)(ITfReadingInformationUIElement *, UINT *);
HRESULT (STDMETHODCALLTYPE *IsVerticalOrderPreferred)(ITfReadingInformationUIElement *, BOOL *);
} ITfReadingInformationUIElementVtbl;
struct ITfReadingInformationUIElement
{
const struct ITfReadingInformationUIElementVtbl *lpVtbl;
};
typedef struct ITfUIElementVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(ITfUIElement *, REFIID, void **);
ULONG (STDMETHODCALLTYPE *AddRef)(ITfUIElement *);
ULONG (STDMETHODCALLTYPE *Release)(ITfUIElement *);
HRESULT (STDMETHODCALLTYPE *GetDescription)(ITfUIElement *, BSTR *);
HRESULT (STDMETHODCALLTYPE *GetGUID)(ITfUIElement *, GUID *);
HRESULT (STDMETHODCALLTYPE *Show)(ITfUIElement *, BOOL);
HRESULT (STDMETHODCALLTYPE *IsShown)(ITfUIElement *, BOOL *);
} ITfUIElementVtbl;
struct ITfUIElement
{
const struct ITfUIElementVtbl *lpVtbl;
};
typedef struct ITfInputProcessorProfileActivationSinkVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(ITfInputProcessorProfileActivationSink *, REFIID, void **);
ULONG (STDMETHODCALLTYPE *AddRef)(ITfInputProcessorProfileActivationSink *);
ULONG (STDMETHODCALLTYPE *Release)(ITfInputProcessorProfileActivationSink *);
HRESULT (STDMETHODCALLTYPE *OnActivated)(ITfInputProcessorProfileActivationSink *, DWORD, LANGID, REFCLSID, REFGUID, REFGUID, HKL, DWORD);
} ITfInputProcessorProfileActivationSinkVtbl;
struct ITfInputProcessorProfileActivationSink
{
const struct ITfInputProcessorProfileActivationSinkVtbl *lpVtbl;
};
typedef struct ITfSourceVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(ITfSource *, REFIID, void **);
ULONG (STDMETHODCALLTYPE *AddRef)(ITfSource *);
ULONG (STDMETHODCALLTYPE *Release)(ITfSource *);
HRESULT (STDMETHODCALLTYPE *AdviseSink)(ITfSource *, REFIID, IUnknown *, DWORD *);
HRESULT (STDMETHODCALLTYPE *UnadviseSink)(ITfSource *, DWORD);
} ITfSourceVtbl;
struct ITfSource
{
const struct ITfSourceVtbl *lpVtbl;
};
/* *INDENT-ON* */ /* clang-format on */
#endif /* SDL_msctf_h_ */

View File

@ -0,0 +1,74 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef VK_0
#define VK_0 '0'
#define VK_1 '1'
#define VK_2 '2'
#define VK_3 '3'
#define VK_4 '4'
#define VK_5 '5'
#define VK_6 '6'
#define VK_7 '7'
#define VK_8 '8'
#define VK_9 '9'
#define VK_A 'A'
#define VK_B 'B'
#define VK_C 'C'
#define VK_D 'D'
#define VK_E 'E'
#define VK_F 'F'
#define VK_G 'G'
#define VK_H 'H'
#define VK_I 'I'
#define VK_J 'J'
#define VK_K 'K'
#define VK_L 'L'
#define VK_M 'M'
#define VK_N 'N'
#define VK_O 'O'
#define VK_P 'P'
#define VK_Q 'Q'
#define VK_R 'R'
#define VK_S 'S'
#define VK_T 'T'
#define VK_U 'U'
#define VK_V 'V'
#define VK_W 'W'
#define VK_X 'X'
#define VK_Y 'Y'
#define VK_Z 'Z'
#endif /* VK_0 */
/* These keys haven't been defined, but were experimentally determined */
#define VK_SEMICOLON 0xBA
#define VK_EQUALS 0xBB
#define VK_COMMA 0xBC
#define VK_MINUS 0xBD
#define VK_PERIOD 0xBE
#define VK_SLASH 0xBF
#define VK_GRAVE 0xC0
#define VK_LBRACKET 0xDB
#define VK_BACKSLASH 0xDC
#define VK_RBRACKET 0xDD
#define VK_APOSTROPHE 0xDE
#define VK_BACKTICK 0xDF
#define VK_OEM_102 0xE2

View File

@ -0,0 +1,346 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_DRIVER_WINDOWS) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
#include "SDL_windowsvideo.h"
#include "SDL_windowswindow.h"
#include "../SDL_clipboard_c.h"
#include "../../events/SDL_clipboardevents_c.h"
#ifdef UNICODE
#define TEXT_FORMAT CF_UNICODETEXT
#else
#define TEXT_FORMAT CF_TEXT
#endif
#define IMAGE_FORMAT CF_DIB
#define IMAGE_MIME_TYPE "image/bmp"
/* Assume we can directly read and write BMP fields without byte swapping */
SDL_COMPILE_TIME_ASSERT(verify_byte_order, SDL_BYTEORDER == SDL_LIL_ENDIAN);
static const char bmp_magic[2] = { 'B', 'M' };
static BOOL WIN_OpenClipboard(SDL_VideoDevice *_this)
{
/* Retry to open the clipboard in case another application has it open */
const int MAX_ATTEMPTS = 3;
int attempt;
HWND hwnd = NULL;
if (_this->windows) {
hwnd = _this->windows->driverdata->hwnd;
}
for (attempt = 0; attempt < MAX_ATTEMPTS; ++attempt) {
if (OpenClipboard(hwnd)) {
return TRUE;
}
SDL_Delay(10);
}
return FALSE;
}
static void WIN_CloseClipboard(void)
{
CloseClipboard();
}
static HANDLE WIN_ConvertBMPtoDIB(const void *bmp, size_t bmp_size)
{
HANDLE hMem = NULL;
if (bmp && bmp_size > sizeof(BITMAPFILEHEADER) && SDL_memcmp(bmp, bmp_magic, sizeof(bmp_magic)) == 0) {
BITMAPFILEHEADER *pbfh = (BITMAPFILEHEADER *)bmp;
BITMAPINFOHEADER *pbih = (BITMAPINFOHEADER *)((Uint8 *)bmp + sizeof(BITMAPFILEHEADER));
size_t bih_size = pbih->biSize + pbih->biClrUsed * sizeof(RGBQUAD);
size_t pixels_size = pbih->biSizeImage;
if (pbfh->bfOffBits >= (sizeof(BITMAPFILEHEADER) + bih_size) &&
(pbfh->bfOffBits + pixels_size) <= bmp_size) {
const Uint8 *pixels = (const Uint8 *)bmp + pbfh->bfOffBits;
size_t dib_size = bih_size + pixels_size;
hMem = GlobalAlloc(GMEM_MOVEABLE, dib_size);
if (hMem) {
LPVOID dst = GlobalLock(hMem);
if (dst) {
SDL_memcpy(dst, pbih, bih_size);
SDL_memcpy((Uint8 *)dst + bih_size, pixels, pixels_size);
GlobalUnlock(hMem);
} else {
WIN_SetError("GlobalLock()");
GlobalFree(hMem);
hMem = NULL;
}
} else {
SDL_OutOfMemory();
}
} else {
SDL_SetError("Invalid BMP data");
}
} else {
SDL_SetError("Invalid BMP data");
}
return hMem;
}
static void *WIN_ConvertDIBtoBMP(HANDLE hMem, size_t *size)
{
void *bmp = NULL;
size_t mem_size = GlobalSize(hMem);
if (mem_size > sizeof(BITMAPINFOHEADER)) {
LPVOID dib = GlobalLock(hMem);
if (dib) {
BITMAPINFOHEADER *pbih = (BITMAPINFOHEADER *)dib;
size_t bih_size = pbih->biSize + pbih->biClrUsed * sizeof(RGBQUAD);
size_t dib_size = bih_size + pbih->biSizeImage;
if (dib_size <= mem_size) {
size_t bmp_size = sizeof(BITMAPFILEHEADER) + dib_size;
bmp = SDL_malloc(bmp_size);
if (bmp) {
BITMAPFILEHEADER *pbfh = (BITMAPFILEHEADER *)bmp;
pbfh->bfType = 0x4d42; /* bmp_magic */
pbfh->bfSize = (DWORD)bmp_size;
pbfh->bfReserved1 = 0;
pbfh->bfReserved2 = 0;
pbfh->bfOffBits = (DWORD)(sizeof(BITMAPFILEHEADER) + bih_size);
SDL_memcpy((Uint8 *)bmp + sizeof(BITMAPFILEHEADER), dib, dib_size);
*size = bmp_size;
} else {
SDL_OutOfMemory();
}
} else {
SDL_SetError("Invalid BMP data");
}
GlobalUnlock(hMem);
} else {
WIN_SetError("GlobalLock()");
}
} else {
SDL_SetError("Invalid BMP data");
}
return bmp;
}
static int WIN_SetClipboardImage(SDL_VideoDevice *_this)
{
HANDLE hMem;
size_t clipboard_data_size;
const void *clipboard_data;
int result = 0;
clipboard_data = _this->clipboard_callback(_this->clipboard_userdata, IMAGE_MIME_TYPE, &clipboard_data_size);
hMem = WIN_ConvertBMPtoDIB(clipboard_data, clipboard_data_size);
if (hMem) {
/* Save the image to the clipboard */
if (!SetClipboardData(IMAGE_FORMAT, hMem)) {
result = WIN_SetError("Couldn't set clipboard data");
}
} else {
/* WIN_ConvertBMPtoDIB() set the error */
result = -1;
}
return result;
}
static int WIN_SetClipboardText(SDL_VideoDevice *_this, const char *mime_type)
{
HANDLE hMem;
size_t clipboard_data_size;
const void *clipboard_data;
int result = 0;
clipboard_data = _this->clipboard_callback(_this->clipboard_userdata, mime_type, &clipboard_data_size);
if (clipboard_data && clipboard_data_size > 0) {
SIZE_T i, size;
LPTSTR tstr = (WCHAR *)SDL_iconv_string("UTF-16LE", "UTF-8", (const char *)clipboard_data, clipboard_data_size);
if (!tstr) {
return SDL_SetError("Couldn't convert text from UTF-8");
}
/* Find out the size of the data */
for (size = 0, i = 0; tstr[i]; ++i, ++size) {
if (tstr[i] == '\n' && (i == 0 || tstr[i - 1] != '\r')) {
/* We're going to insert a carriage return */
++size;
}
}
size = (size + 1) * sizeof(*tstr);
/* Save the data to the clipboard */
hMem = GlobalAlloc(GMEM_MOVEABLE, size);
if (hMem) {
LPTSTR dst = (LPTSTR)GlobalLock(hMem);
if (dst) {
/* Copy the text over, adding carriage returns as necessary */
for (i = 0; tstr[i]; ++i) {
if (tstr[i] == '\n' && (i == 0 || tstr[i - 1] != '\r')) {
*dst++ = '\r';
}
*dst++ = tstr[i];
}
*dst = 0;
GlobalUnlock(hMem);
}
if (!SetClipboardData(TEXT_FORMAT, hMem)) {
result = WIN_SetError("Couldn't set clipboard data");
}
} else {
result = SDL_OutOfMemory();
}
SDL_free(tstr);
}
return result;
}
int WIN_SetClipboardData(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->driverdata;
size_t i;
int result = 0;
/* I investigated delayed clipboard rendering, and at least with text and image
* formats you have to use an output window, not SDL_HelperWindow, and the system
* requests them being rendered immediately, so there isn't any benefit.
*/
if (WIN_OpenClipboard(_this)) {
EmptyClipboard();
/* Set the clipboard text */
for (i = 0; i < _this->num_clipboard_mime_types; ++i) {
const char *mime_type = _this->clipboard_mime_types[i];
if (SDL_IsTextMimeType(mime_type)) {
if (WIN_SetClipboardText(_this, mime_type) < 0) {
result = -1;
}
/* Only set the first clipboard text */
break;
}
}
/* Set the clipboard image */
for (i = 0; i < _this->num_clipboard_mime_types; ++i) {
const char *mime_type = _this->clipboard_mime_types[i];
if (SDL_strcmp(mime_type, IMAGE_MIME_TYPE) == 0) {
if (WIN_SetClipboardImage(_this) < 0) {
result = -1;
}
break;
}
}
data->clipboard_count = GetClipboardSequenceNumber();
WIN_CloseClipboard();
} else {
result = WIN_SetError("Couldn't open clipboard");
}
return result;
}
void *WIN_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size)
{
void *data = NULL;
if (SDL_IsTextMimeType(mime_type)) {
char *text = NULL;
if (IsClipboardFormatAvailable(TEXT_FORMAT)) {
if (WIN_OpenClipboard(_this)) {
HANDLE hMem;
LPTSTR tstr;
hMem = GetClipboardData(TEXT_FORMAT);
if (hMem) {
tstr = (LPTSTR)GlobalLock(hMem);
if (tstr) {
text = WIN_StringToUTF8(tstr);
GlobalUnlock(hMem);
} else {
WIN_SetError("Couldn't lock clipboard data");
}
} else {
WIN_SetError("Couldn't get clipboard data");
}
WIN_CloseClipboard();
}
}
if (text == NULL) {
text = SDL_strdup("");
}
data = text;
*size = SDL_strlen(text);
} else if (SDL_strcmp(mime_type, IMAGE_MIME_TYPE) == 0) {
if (IsClipboardFormatAvailable(IMAGE_FORMAT)) {
if (WIN_OpenClipboard(_this)) {
HANDLE hMem;
hMem = GetClipboardData(IMAGE_FORMAT);
if (hMem) {
data = WIN_ConvertDIBtoBMP(hMem, size);
} else {
WIN_SetError("Couldn't get clipboard data");
}
WIN_CloseClipboard();
}
}
} else {
data = SDL_GetInternalClipboardData(_this, mime_type, size);
}
return data;
}
SDL_bool WIN_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
{
if (SDL_IsTextMimeType(mime_type)) {
if (IsClipboardFormatAvailable(TEXT_FORMAT)) {
return SDL_TRUE;
}
} else if (SDL_strcmp(mime_type, IMAGE_MIME_TYPE) == 0) {
if (IsClipboardFormatAvailable(IMAGE_FORMAT)) {
return SDL_TRUE;
}
} else {
if (SDL_HasInternalClipboardData(_this, mime_type)) {
return SDL_TRUE;
}
}
return SDL_FALSE;
}
void WIN_CheckClipboardUpdate(struct SDL_VideoData *data)
{
const DWORD count = GetClipboardSequenceNumber();
if (count != data->clipboard_count) {
if (data->clipboard_count) {
SDL_SendClipboardUpdate();
}
data->clipboard_count = count;
}
}
#endif /* SDL_VIDEO_DRIVER_WINDOWS */

View File

@ -0,0 +1,34 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_windowsclipboard_h_
#define SDL_windowsclipboard_h_
/* Forward declaration */
struct SDL_VideoData;
extern int WIN_SetClipboardData(SDL_VideoDevice *_this);
extern void *WIN_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size);
extern SDL_bool WIN_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type);
extern void WIN_CheckClipboardUpdate(struct SDL_VideoData *data);
#endif /* SDL_windowsclipboard_h_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_windowsevents_h_
#define SDL_windowsevents_h_
extern LPTSTR SDL_Appname;
extern Uint32 SDL_Appstyle;
extern HINSTANCE SDL_Instance;
extern LRESULT CALLBACK WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam);
extern LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam);
extern void WIN_PumpEvents(SDL_VideoDevice *_this);
extern void WIN_SendWakeupEvent(SDL_VideoDevice *_this, SDL_Window *window);
extern int WIN_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS);
#endif /* SDL_windowsevents_h_ */

View File

@ -0,0 +1,132 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_DRIVER_WINDOWS) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
#include "SDL_windowsvideo.h"
int WIN_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, Uint32 *format, void **pixels, int *pitch)
{
SDL_WindowData *data = window->driverdata;
SDL_bool isstack;
size_t size;
LPBITMAPINFO info;
HBITMAP hbm;
int w, h;
SDL_GetWindowSizeInPixels(window, &w, &h);
/* Free the old framebuffer surface */
if (data->mdc) {
DeleteDC(data->mdc);
}
if (data->hbm) {
DeleteObject(data->hbm);
}
/* Find out the format of the screen */
size = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
info = (LPBITMAPINFO)SDL_small_alloc(Uint8, size, &isstack);
if (!info) {
return SDL_OutOfMemory();
}
SDL_memset(info, 0, size);
info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
/* The second call to GetDIBits() fills in the bitfields */
hbm = CreateCompatibleBitmap(data->hdc, 1, 1);
GetDIBits(data->hdc, hbm, 0, 0, NULL, info, DIB_RGB_COLORS);
GetDIBits(data->hdc, hbm, 0, 0, NULL, info, DIB_RGB_COLORS);
DeleteObject(hbm);
*format = SDL_PIXELFORMAT_UNKNOWN;
if (info->bmiHeader.biCompression == BI_BITFIELDS) {
int bpp;
Uint32 *masks;
bpp = info->bmiHeader.biPlanes * info->bmiHeader.biBitCount;
masks = (Uint32 *)((Uint8 *)info + info->bmiHeader.biSize);
*format = SDL_GetPixelFormatEnumForMasks(bpp, masks[0], masks[1], masks[2], 0);
}
if (*format == SDL_PIXELFORMAT_UNKNOWN) {
/* We'll use RGB format for now */
*format = SDL_PIXELFORMAT_XRGB8888;
/* Create a new one */
SDL_memset(info, 0, size);
info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
info->bmiHeader.biPlanes = 1;
info->bmiHeader.biBitCount = 32;
info->bmiHeader.biCompression = BI_RGB;
}
/* Fill in the size information */
*pitch = (((w * SDL_BYTESPERPIXEL(*format)) + 3) & ~3);
info->bmiHeader.biWidth = w;
info->bmiHeader.biHeight = -h; /* negative for topdown bitmap */
info->bmiHeader.biSizeImage = (DWORD)h * (*pitch);
data->mdc = CreateCompatibleDC(data->hdc);
data->hbm = CreateDIBSection(data->hdc, info, DIB_RGB_COLORS, pixels, NULL, 0);
SDL_small_free(info, isstack);
if (!data->hbm) {
return WIN_SetError("Unable to create DIB");
}
SelectObject(data->mdc, data->hbm);
return 0;
}
int WIN_UpdateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, const SDL_Rect *rects, int numrects)
{
SDL_WindowData *data = window->driverdata;
int i;
for (i = 0; i < numrects; ++i) {
BitBlt(data->hdc, rects[i].x, rects[i].y, rects[i].w, rects[i].h,
data->mdc, rects[i].x, rects[i].y, SRCCOPY);
}
return 0;
}
void WIN_DestroyWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
if (data == NULL) {
/* The window wasn't fully initialized */
return;
}
if (data->mdc) {
DeleteDC(data->mdc);
data->mdc = NULL;
}
if (data->hbm) {
DeleteObject(data->hbm);
data->hbm = NULL;
}
}
#endif /* SDL_VIDEO_DRIVER_WINDOWS */

View File

@ -0,0 +1,25 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
extern int WIN_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, Uint32 *format, void **pixels, int *pitch);
extern int WIN_UpdateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, const SDL_Rect *rects, int numrects);
extern void WIN_DestroyWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_windowskeyboard_h_
#define SDL_windowskeyboard_h_
extern void WIN_InitKeyboard(SDL_VideoDevice *_this);
extern void WIN_UpdateKeymap(SDL_bool send_event);
extern void WIN_QuitKeyboard(SDL_VideoDevice *_this);
extern void WIN_ResetDeadKeys(void);
extern void WIN_StartTextInput(SDL_VideoDevice *_this);
extern void WIN_StopTextInput(SDL_VideoDevice *_this);
extern int WIN_SetTextInputRect(SDL_VideoDevice *_this, const SDL_Rect *rect);
extern void WIN_ClearComposition(SDL_VideoDevice *_this);
extern SDL_bool WIN_IsTextInputShown(SDL_VideoDevice *_this);
extern SDL_bool IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, struct SDL_VideoData *videodata);
#endif /* SDL_windowskeyboard_h_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_WINDOWS
extern int WIN_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid);
#endif /* SDL_VIDEO_DRIVER_WINDOWS */

View File

@ -0,0 +1,681 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_DRIVER_WINDOWS) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
#include "SDL_windowsvideo.h"
#include "../../events/SDL_displayevents_c.h"
/* Windows CE compatibility */
#ifndef CDS_FULLSCREEN
#define CDS_FULLSCREEN 0
#endif
/* #define DEBUG_MODES */
/* #define HIGHDPI_DEBUG_VERBOSE */
static void WIN_UpdateDisplayMode(SDL_VideoDevice *_this, LPCWSTR deviceName, DWORD index, SDL_DisplayMode *mode)
{
SDL_DisplayModeData *data = (SDL_DisplayModeData *)mode->driverdata;
HDC hdc;
data->DeviceMode.dmFields = (DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS);
/* NOLINTNEXTLINE(bugprone-assignment-in-if-condition): No simple way to extract the assignment */
if (index == ENUM_CURRENT_SETTINGS && (hdc = CreateDC(deviceName, NULL, NULL, NULL)) != NULL) {
char bmi_data[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];
LPBITMAPINFO bmi;
HBITMAP hbm;
SDL_zeroa(bmi_data);
bmi = (LPBITMAPINFO)bmi_data;
bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
hbm = CreateCompatibleBitmap(hdc, 1, 1);
GetDIBits(hdc, hbm, 0, 1, NULL, bmi, DIB_RGB_COLORS);
GetDIBits(hdc, hbm, 0, 1, NULL, bmi, DIB_RGB_COLORS);
DeleteObject(hbm);
DeleteDC(hdc);
if (bmi->bmiHeader.biCompression == BI_BITFIELDS) {
switch (*(Uint32 *)bmi->bmiColors) {
case 0x00FF0000:
mode->format = SDL_PIXELFORMAT_XRGB8888;
break;
case 0x000000FF:
mode->format = SDL_PIXELFORMAT_XBGR8888;
break;
case 0xF800:
mode->format = SDL_PIXELFORMAT_RGB565;
break;
case 0x7C00:
mode->format = SDL_PIXELFORMAT_RGB555;
break;
}
} else if (bmi->bmiHeader.biBitCount == 8) {
mode->format = SDL_PIXELFORMAT_INDEX8;
} else if (bmi->bmiHeader.biBitCount == 4) {
mode->format = SDL_PIXELFORMAT_INDEX4LSB;
}
} else if (mode->format == SDL_PIXELFORMAT_UNKNOWN) {
/* FIXME: Can we tell what this will be? */
if ((data->DeviceMode.dmFields & DM_BITSPERPEL) == DM_BITSPERPEL) {
switch (data->DeviceMode.dmBitsPerPel) {
case 32:
mode->format = SDL_PIXELFORMAT_XRGB8888;
break;
case 24:
mode->format = SDL_PIXELFORMAT_RGB24;
break;
case 16:
mode->format = SDL_PIXELFORMAT_RGB565;
break;
case 15:
mode->format = SDL_PIXELFORMAT_RGB555;
break;
case 8:
mode->format = SDL_PIXELFORMAT_INDEX8;
break;
case 4:
mode->format = SDL_PIXELFORMAT_INDEX4LSB;
break;
}
}
}
}
static SDL_DisplayOrientation WIN_GetNaturalOrientation(DEVMODE *mode)
{
int width = mode->dmPelsWidth;
int height = mode->dmPelsHeight;
/* Use unrotated width/height to guess orientation */
if (mode->dmDisplayOrientation == DMDO_90 || mode->dmDisplayOrientation == DMDO_270) {
int temp = width;
width = height;
height = temp;
}
if (width >= height) {
return SDL_ORIENTATION_LANDSCAPE;
} else {
return SDL_ORIENTATION_PORTRAIT;
}
}
static SDL_DisplayOrientation WIN_GetDisplayOrientation(DEVMODE *mode)
{
if (WIN_GetNaturalOrientation(mode) == SDL_ORIENTATION_LANDSCAPE) {
switch (mode->dmDisplayOrientation) {
case DMDO_DEFAULT:
return SDL_ORIENTATION_LANDSCAPE;
case DMDO_90:
return SDL_ORIENTATION_PORTRAIT;
case DMDO_180:
return SDL_ORIENTATION_LANDSCAPE_FLIPPED;
case DMDO_270:
return SDL_ORIENTATION_PORTRAIT_FLIPPED;
default:
return SDL_ORIENTATION_UNKNOWN;
}
} else {
switch (mode->dmDisplayOrientation) {
case DMDO_DEFAULT:
return SDL_ORIENTATION_PORTRAIT;
case DMDO_90:
return SDL_ORIENTATION_LANDSCAPE_FLIPPED;
case DMDO_180:
return SDL_ORIENTATION_PORTRAIT_FLIPPED;
case DMDO_270:
return SDL_ORIENTATION_LANDSCAPE;
default:
return SDL_ORIENTATION_UNKNOWN;
}
}
}
static float WIN_GetRefreshRate(DEVMODE *mode)
{
/* We're not currently using DXGI to query display modes, so fake NTSC timings */
switch (mode->dmDisplayFrequency) {
case 119:
case 59:
case 29:
return ((100 * (mode->dmDisplayFrequency + 1) * 1000) / 1001) / 100.0f;
default:
return (float)mode->dmDisplayFrequency;
}
}
static float WIN_GetContentScale(SDL_VideoDevice *_this, HMONITOR hMonitor)
{
const SDL_VideoData *videodata = (const SDL_VideoData *)_this->driverdata;
int dpi = 0;
if (videodata->GetDpiForMonitor) {
UINT hdpi_uint, vdpi_uint;
if (videodata->GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &hdpi_uint, &vdpi_uint) == S_OK) {
dpi = (int)hdpi_uint;
}
}
if (dpi == 0) {
/* Window 8.0 and below: same DPI for all monitors */
HDC hdc = GetDC(NULL);
if (hdc) {
dpi = GetDeviceCaps(hdc, LOGPIXELSX);
ReleaseDC(NULL, hdc);
}
}
if (dpi == 0) {
/* Safe default */
dpi = 96;
}
return dpi / 96.0f;
}
static SDL_bool WIN_GetDisplayMode(SDL_VideoDevice *_this, HMONITOR hMonitor, LPCWSTR deviceName, DWORD index, SDL_DisplayMode *mode, SDL_DisplayOrientation *natural_orientation, SDL_DisplayOrientation *current_orientation)
{
SDL_DisplayModeData *data;
DEVMODE devmode;
devmode.dmSize = sizeof(devmode);
devmode.dmDriverExtra = 0;
if (!EnumDisplaySettingsW(deviceName, index, &devmode)) {
return SDL_FALSE;
}
data = (SDL_DisplayModeData *)SDL_malloc(sizeof(*data));
if (data == NULL) {
return SDL_FALSE;
}
SDL_zerop(mode);
mode->driverdata = data;
data->DeviceMode = devmode;
mode->format = SDL_PIXELFORMAT_UNKNOWN;
mode->w = data->DeviceMode.dmPelsWidth;
mode->h = data->DeviceMode.dmPelsHeight;
mode->refresh_rate = WIN_GetRefreshRate(&data->DeviceMode);
/* Fill in the mode information */
WIN_UpdateDisplayMode(_this, deviceName, index, mode);
if (natural_orientation) {
*natural_orientation = WIN_GetNaturalOrientation(&devmode);
}
if (current_orientation) {
*current_orientation = WIN_GetDisplayOrientation(&devmode);
}
return SDL_TRUE;
}
/* The win32 API calls in this function require Windows Vista or later. */
/* *INDENT-OFF* */ /* clang-format off */
typedef LONG (WINAPI *SDL_WIN32PROC_GetDisplayConfigBufferSizes)(UINT32 flags, UINT32* numPathArrayElements, UINT32* numModeInfoArrayElements);
typedef LONG (WINAPI *SDL_WIN32PROC_QueryDisplayConfig)(UINT32 flags, UINT32* numPathArrayElements, DISPLAYCONFIG_PATH_INFO* pathArray, UINT32* numModeInfoArrayElements, DISPLAYCONFIG_MODE_INFO* modeInfoArray, DISPLAYCONFIG_TOPOLOGY_ID* currentTopologyId);
typedef LONG (WINAPI *SDL_WIN32PROC_DisplayConfigGetDeviceInfo)(DISPLAYCONFIG_DEVICE_INFO_HEADER* requestPacket);
/* *INDENT-ON* */ /* clang-format on */
static char *WIN_GetDisplayNameVista(const WCHAR *deviceName)
{
void *dll;
SDL_WIN32PROC_GetDisplayConfigBufferSizes pGetDisplayConfigBufferSizes;
SDL_WIN32PROC_QueryDisplayConfig pQueryDisplayConfig;
SDL_WIN32PROC_DisplayConfigGetDeviceInfo pDisplayConfigGetDeviceInfo;
DISPLAYCONFIG_PATH_INFO *paths = NULL;
DISPLAYCONFIG_MODE_INFO *modes = NULL;
char *retval = NULL;
UINT32 pathCount = 0;
UINT32 modeCount = 0;
UINT32 i;
LONG rc;
dll = SDL_LoadObject("USER32.DLL");
if (dll == NULL) {
return NULL;
}
pGetDisplayConfigBufferSizes = (SDL_WIN32PROC_GetDisplayConfigBufferSizes)SDL_LoadFunction(dll, "GetDisplayConfigBufferSizes");
pQueryDisplayConfig = (SDL_WIN32PROC_QueryDisplayConfig)SDL_LoadFunction(dll, "QueryDisplayConfig");
pDisplayConfigGetDeviceInfo = (SDL_WIN32PROC_DisplayConfigGetDeviceInfo)SDL_LoadFunction(dll, "DisplayConfigGetDeviceInfo");
if (pGetDisplayConfigBufferSizes == NULL || pQueryDisplayConfig == NULL || pDisplayConfigGetDeviceInfo == NULL) {
goto WIN_GetDisplayNameVista_failed;
}
do {
rc = pGetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount);
if (rc != ERROR_SUCCESS) {
goto WIN_GetDisplayNameVista_failed;
}
SDL_free(paths);
SDL_free(modes);
paths = (DISPLAYCONFIG_PATH_INFO *)SDL_malloc(sizeof(DISPLAYCONFIG_PATH_INFO) * pathCount);
modes = (DISPLAYCONFIG_MODE_INFO *)SDL_malloc(sizeof(DISPLAYCONFIG_MODE_INFO) * modeCount);
if ((paths == NULL) || (modes == NULL)) {
goto WIN_GetDisplayNameVista_failed;
}
rc = pQueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathCount, paths, &modeCount, modes, 0);
} while (rc == ERROR_INSUFFICIENT_BUFFER);
if (rc == ERROR_SUCCESS) {
for (i = 0; i < pathCount; i++) {
DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName;
DISPLAYCONFIG_TARGET_DEVICE_NAME targetName;
SDL_zero(sourceName);
sourceName.header.adapterId = paths[i].targetInfo.adapterId;
sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
sourceName.header.size = sizeof(sourceName);
sourceName.header.id = paths[i].sourceInfo.id;
rc = pDisplayConfigGetDeviceInfo(&sourceName.header);
if (rc != ERROR_SUCCESS) {
break;
} else if (SDL_wcscmp(deviceName, sourceName.viewGdiDeviceName) != 0) {
continue;
}
SDL_zero(targetName);
targetName.header.adapterId = paths[i].targetInfo.adapterId;
targetName.header.id = paths[i].targetInfo.id;
targetName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
targetName.header.size = sizeof(targetName);
rc = pDisplayConfigGetDeviceInfo(&targetName.header);
if (rc == ERROR_SUCCESS) {
retval = WIN_StringToUTF8W(targetName.monitorFriendlyDeviceName);
/* if we got an empty string, treat it as failure so we'll fallback
to getting the generic name. */
if (retval && (*retval == '\0')) {
SDL_free(retval);
retval = NULL;
}
}
break;
}
}
SDL_free(paths);
SDL_free(modes);
SDL_UnloadObject(dll);
return retval;
WIN_GetDisplayNameVista_failed:
SDL_free(retval);
SDL_free(paths);
SDL_free(modes);
SDL_UnloadObject(dll);
return NULL;
}
static void WIN_AddDisplay(SDL_VideoDevice *_this, HMONITOR hMonitor, const MONITORINFOEXW *info, int *display_index)
{
int i, index = *display_index;
SDL_VideoDisplay display;
SDL_DisplayData *displaydata;
SDL_DisplayMode mode;
SDL_DisplayOrientation natural_orientation;
SDL_DisplayOrientation current_orientation;
float content_scale = WIN_GetContentScale(_this, hMonitor);
#ifdef DEBUG_MODES
SDL_Log("Display: %s\n", WIN_StringToUTF8W(info->szDevice));
#endif
if (!WIN_GetDisplayMode(_this, hMonitor, info->szDevice, ENUM_CURRENT_SETTINGS, &mode, &natural_orientation, &current_orientation)) {
return;
}
// Prevent adding duplicate displays. Do this after we know the display is
// ready to be added to allow any displays that we can't fully query to be
// removed
for (i = 0; i < _this->num_displays; ++i) {
SDL_DisplayData *driverdata = _this->displays[i].driverdata;
if (SDL_wcscmp(driverdata->DeviceName, info->szDevice) == 0) {
SDL_bool moved = (index != i);
SDL_bool changed_bounds = SDL_FALSE;
if (moved) {
SDL_VideoDisplay tmp;
SDL_assert(index < _this->num_displays);
SDL_memcpy(&tmp, &_this->displays[index], sizeof(tmp));
SDL_memcpy(&_this->displays[index], &_this->displays[i], sizeof(tmp));
SDL_memcpy(&_this->displays[i], &tmp, sizeof(tmp));
i = index;
}
driverdata->MonitorHandle = hMonitor;
driverdata->state = DisplayUnchanged;
if (!_this->setting_display_mode) {
SDL_VideoDisplay *existing_display = &_this->displays[i];
SDL_Rect bounds;
SDL_ResetFullscreenDisplayModes(existing_display);
SDL_SetDesktopDisplayMode(existing_display, &mode);
if (WIN_GetDisplayBounds(_this, existing_display, &bounds) == 0 &&
SDL_memcmp(&driverdata->bounds, &bounds, sizeof(bounds)) != 0) {
changed_bounds = SDL_TRUE;
SDL_copyp(&driverdata->bounds, &bounds);
}
if (moved || changed_bounds) {
SDL_SendDisplayEvent(existing_display, SDL_EVENT_DISPLAY_MOVED, 0);
}
SDL_SendDisplayEvent(existing_display, SDL_EVENT_DISPLAY_ORIENTATION, current_orientation);
SDL_SetDisplayContentScale(existing_display, content_scale);
}
goto done;
}
}
displaydata = (SDL_DisplayData *)SDL_calloc(1, sizeof(*displaydata));
if (displaydata == NULL) {
return;
}
SDL_memcpy(displaydata->DeviceName, info->szDevice, sizeof(displaydata->DeviceName));
displaydata->MonitorHandle = hMonitor;
displaydata->state = DisplayAdded;
SDL_zero(display);
display.name = WIN_GetDisplayNameVista(info->szDevice);
if (display.name == NULL) {
DISPLAY_DEVICEW device;
SDL_zero(device);
device.cb = sizeof(device);
if (EnumDisplayDevicesW(info->szDevice, 0, &device, 0)) {
display.name = WIN_StringToUTF8W(device.DeviceString);
}
}
display.desktop_mode = mode;
display.natural_orientation = natural_orientation;
display.current_orientation = current_orientation;
display.content_scale = content_scale;
display.device = _this;
display.driverdata = displaydata;
WIN_GetDisplayBounds(_this, &display, &displaydata->bounds);
SDL_AddVideoDisplay(&display, SDL_FALSE);
SDL_free(display.name);
done:
*display_index += 1;
}
typedef struct _WIN_AddDisplaysData
{
SDL_VideoDevice *video_device;
int display_index;
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;
MONITORINFOEXW info;
SDL_zero(info);
info.cbSize = sizeof(info);
if (GetMonitorInfoW(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, &data->display_index);
}
}
// continue enumeration
return TRUE;
}
static void WIN_AddDisplays(SDL_VideoDevice *_this)
{
WIN_AddDisplaysData callback_data;
callback_data.video_device = _this;
callback_data.display_index = 0;
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(SDL_VideoDevice *_this)
{
WIN_AddDisplays(_this);
if (_this->num_displays == 0) {
return SDL_SetError("No displays available");
}
return 0;
}
int WIN_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect)
{
const SDL_DisplayData *data = 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.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_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect)
{
const SDL_DisplayData *data = 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;
}
int WIN_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display)
{
SDL_DisplayData *data = display->driverdata;
DWORD i;
SDL_DisplayMode mode;
for (i = 0;; ++i) {
if (!WIN_GetDisplayMode(_this, data->MonitorHandle, data->DeviceName, i, &mode, NULL, NULL)) {
break;
}
if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
/* We don't support palettized modes now */
SDL_free(mode.driverdata);
continue;
}
if (mode.format != SDL_PIXELFORMAT_UNKNOWN) {
if (!SDL_AddFullscreenDisplayMode(display, &mode)) {
SDL_free(mode.driverdata);
}
} else {
SDL_free(mode.driverdata);
}
}
return 0;
}
#ifdef DEBUG_MODES
static void WIN_LogMonitor(SDL_VideoDevice *_this, HMONITOR mon)
{
const SDL_VideoData *vid_data = (const SDL_VideoData *)_this->driverdata;
MONITORINFOEX minfo;
UINT xdpi = 0, ydpi = 0;
char *name_utf8;
if (vid_data->GetDpiForMonitor) {
vid_data->GetDpiForMonitor(mon, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);
}
SDL_zero(minfo);
minfo.cbSize = sizeof(minfo);
GetMonitorInfo(mon, (LPMONITORINFO)&minfo);
name_utf8 = WIN_StringToUTF8(minfo.szDevice);
SDL_Log("WIN_LogMonitor: monitor \"%s\": dpi: %d windows screen coordinates: %d, %d, %dx%d",
name_utf8,
xdpi,
minfo.rcMonitor.left,
minfo.rcMonitor.top,
minfo.rcMonitor.right - minfo.rcMonitor.left,
minfo.rcMonitor.bottom - minfo.rcMonitor.top);
SDL_free(name_utf8);
}
#endif
int WIN_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
{
SDL_DisplayData *displaydata = display->driverdata;
SDL_DisplayModeData *data = mode->driverdata;
LONG status;
#ifdef DEBUG_MODES
SDL_Log("WIN_SetDisplayMode: monitor state before mode change:");
WIN_LogMonitor(_this, displaydata->MonitorHandle);
#endif
/* High-DPI notes:
- ChangeDisplaySettingsEx always takes pixels.
- e.g. if the display is set to 2880x1800 with 200% scaling in Display Settings
- calling ChangeDisplaySettingsEx with a dmPelsWidth/Height other than 2880x1800 will
change the monitor DPI to 96. (100% scaling)
- calling ChangeDisplaySettingsEx with a dmPelsWidth/Height of 2880x1800 (or a NULL DEVMODE*) will
reset the monitor DPI to 192. (200% scaling)
NOTE: these are temporary changes in DPI, not modifications to the Control Panel setting. */
if (mode->driverdata == display->desktop_mode.driverdata) {
#ifdef DEBUG_MODES
SDL_Log("WIN_SetDisplayMode: resetting to original resolution");
#endif
status = ChangeDisplaySettingsExW(displaydata->DeviceName, NULL, NULL, CDS_FULLSCREEN, NULL);
} else {
#ifdef DEBUG_MODES
SDL_Log("WIN_SetDisplayMode: changing to %dx%d pixels", data->DeviceMode.dmPelsWidth, data->DeviceMode.dmPelsHeight);
#endif
status = ChangeDisplaySettingsExW(displaydata->DeviceName, &data->DeviceMode, NULL, CDS_FULLSCREEN, NULL);
}
if (status != DISP_CHANGE_SUCCESSFUL) {
const char *reason = "Unknown reason";
switch (status) {
case DISP_CHANGE_BADFLAGS:
reason = "DISP_CHANGE_BADFLAGS";
break;
case DISP_CHANGE_BADMODE:
reason = "DISP_CHANGE_BADMODE";
break;
case DISP_CHANGE_BADPARAM:
reason = "DISP_CHANGE_BADPARAM";
break;
case DISP_CHANGE_FAILED:
reason = "DISP_CHANGE_FAILED";
break;
}
return SDL_SetError("ChangeDisplaySettingsEx() failed: %s", reason);
}
#ifdef DEBUG_MODES
SDL_Log("WIN_SetDisplayMode: monitor state after mode change:");
WIN_LogMonitor(_this, displaydata->MonitorHandle);
#endif
EnumDisplaySettingsW(displaydata->DeviceName, ENUM_CURRENT_SETTINGS, &data->DeviceMode);
WIN_UpdateDisplayMode(_this, displaydata->DeviceName, ENUM_CURRENT_SETTINGS, mode);
return 0;
}
void WIN_RefreshDisplays(SDL_VideoDevice *_this)
{
int i;
// Mark all displays as potentially invalid to detect
// entries that have actually been removed
for (i = 0; i < _this->num_displays; ++i) {
SDL_DisplayData *driverdata = _this->displays[i].driverdata;
driverdata->state = DisplayRemoved;
}
// Enumerate displays to add any new ones and mark still
// connected entries as valid
WIN_AddDisplays(_this);
// Delete any entries still marked as invalid, iterate
// in reverse as each delete takes effect immediately
for (i = _this->num_displays - 1; i >= 0; --i) {
SDL_VideoDisplay *display = &_this->displays[i];
SDL_DisplayData *driverdata = display->driverdata;
if (driverdata->state == DisplayRemoved) {
SDL_DelVideoDisplay(display->id, SDL_TRUE);
}
}
// Send events for any newly added displays
for (i = 0; i < _this->num_displays; ++i) {
SDL_VideoDisplay *display = &_this->displays[i];
SDL_DisplayData *driverdata = display->driverdata;
if (driverdata->state == DisplayAdded) {
SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_CONNECTED, 0);
}
}
}
void WIN_QuitModes(SDL_VideoDevice *_this)
{
/* All fullscreen windows should have restored modes by now */
}
#endif /* SDL_VIDEO_DRIVER_WINDOWS */

View File

@ -0,0 +1,55 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_windowsmodes_h_
#define SDL_windowsmodes_h_
typedef enum
{
DisplayUnchanged,
DisplayAdded,
DisplayRemoved,
} WIN_DisplayState;
struct SDL_DisplayData
{
WCHAR DeviceName[32];
HMONITOR MonitorHandle;
WIN_DisplayState state;
SDL_Rect bounds;
};
struct SDL_DisplayModeData
{
DEVMODE DeviceMode;
};
extern int WIN_InitModes(SDL_VideoDevice *_this);
extern int WIN_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect);
extern int WIN_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect);
extern int WIN_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display);
extern int WIN_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
extern void WIN_RefreshDisplays(SDL_VideoDevice *_this);
extern void WIN_QuitModes(SDL_VideoDevice *_this);
#endif /* SDL_windowsmodes_h_ */

View File

@ -0,0 +1,488 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_DRIVER_WINDOWS) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
#include "SDL_windowsvideo.h"
#include "../../events/SDL_mouse_c.h"
DWORD SDL_last_warp_time = 0;
HCURSOR SDL_cursor = NULL;
static SDL_Cursor *SDL_blank_cursor = NULL;
static int rawInputEnableCount = 0;
static int ToggleRawInput(SDL_bool enabled)
{
RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */
if (enabled) {
rawInputEnableCount++;
if (rawInputEnableCount > 1) {
return 0; /* already done. */
}
} else {
if (rawInputEnableCount == 0) {
return 0; /* already done. */
}
rawInputEnableCount--;
if (rawInputEnableCount > 0) {
return 0; /* not time to disable yet */
}
}
if (!enabled) {
rawMouse.dwFlags |= RIDEV_REMOVE;
}
/* (Un)register raw input for mice */
if (RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)) == FALSE) {
/* Reset the enable count, otherwise subsequent enable calls will
believe raw input is enabled */
rawInputEnableCount = 0;
/* Only return an error when registering. If we unregister and fail,
then it's probably that we unregistered twice. That's OK. */
if (enabled) {
return SDL_Unsupported();
}
}
return 0;
}
static SDL_Cursor *WIN_CreateDefaultCursor()
{
SDL_Cursor *cursor;
cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
cursor->driverdata = LoadCursor(NULL, IDC_ARROW);
} else {
SDL_OutOfMemory();
}
return cursor;
}
static SDL_Cursor *WIN_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
{
/* msdn says cursor mask has to be padded out to word alignment. Not sure
if that means machine word or WORD, but this handles either case. */
const size_t pad = (sizeof(size_t) * 8); /* 32 or 64, or whatever. */
SDL_Cursor *cursor;
HICON hicon;
HICON hcursor;
HDC hdc;
BITMAPV4HEADER bmh;
LPVOID pixels;
LPVOID maskbits;
size_t maskbitslen;
SDL_bool isstack;
ICONINFO ii;
SDL_zero(bmh);
bmh.bV4Size = sizeof(bmh);
bmh.bV4Width = surface->w;
bmh.bV4Height = -surface->h; /* Invert the image */
bmh.bV4Planes = 1;
bmh.bV4BitCount = 32;
bmh.bV4V4Compression = BI_BITFIELDS;
bmh.bV4AlphaMask = 0xFF000000;
bmh.bV4RedMask = 0x00FF0000;
bmh.bV4GreenMask = 0x0000FF00;
bmh.bV4BlueMask = 0x000000FF;
maskbitslen = ((surface->w + (pad - (surface->w % pad))) / 8) * surface->h;
maskbits = SDL_small_alloc(Uint8, maskbitslen, &isstack);
if (maskbits == NULL) {
SDL_OutOfMemory();
return NULL;
}
/* AND the cursor against full bits: no change. We already have alpha. */
SDL_memset(maskbits, 0xFF, maskbitslen);
hdc = GetDC(NULL);
SDL_zero(ii);
ii.fIcon = FALSE;
ii.xHotspot = (DWORD)hot_x;
ii.yHotspot = (DWORD)hot_y;
ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO *)&bmh, DIB_RGB_COLORS, &pixels, NULL, 0);
ii.hbmMask = CreateBitmap(surface->w, surface->h, 1, 1, maskbits);
ReleaseDC(NULL, hdc);
SDL_small_free(maskbits, isstack);
SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
SDL_assert(surface->pitch == surface->w * 4);
SDL_memcpy(pixels, surface->pixels, (size_t)surface->h * surface->pitch);
hicon = CreateIconIndirect(&ii);
DeleteObject(ii.hbmColor);
DeleteObject(ii.hbmMask);
if (!hicon) {
WIN_SetError("CreateIconIndirect()");
return NULL;
}
/* The cursor returned by CreateIconIndirect does not respect system cursor size
preference, use CopyImage to duplicate the cursor with desired sizes */
hcursor = CopyImage(hicon, IMAGE_CURSOR, surface->w, surface->h, 0);
DestroyIcon(hicon);
if (!hcursor) {
WIN_SetError("CopyImage()");
return NULL;
}
cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
cursor->driverdata = hcursor;
} else {
DestroyIcon(hcursor);
SDL_OutOfMemory();
}
return cursor;
}
static SDL_Cursor *WIN_CreateBlankCursor()
{
SDL_Cursor *cursor = NULL;
SDL_Surface *surface = SDL_CreateSurface(32, 32, SDL_PIXELFORMAT_ARGB8888);
if (surface) {
cursor = WIN_CreateCursor(surface, 0, 0);
SDL_DestroySurface(surface);
}
return cursor;
}
static SDL_Cursor *WIN_CreateSystemCursor(SDL_SystemCursor id)
{
SDL_Cursor *cursor;
LPCTSTR name;
switch (id) {
default:
SDL_assert(0);
return NULL;
case SDL_SYSTEM_CURSOR_ARROW:
name = IDC_ARROW;
break;
case SDL_SYSTEM_CURSOR_IBEAM:
name = IDC_IBEAM;
break;
case SDL_SYSTEM_CURSOR_WAIT:
name = IDC_WAIT;
break;
case SDL_SYSTEM_CURSOR_CROSSHAIR:
name = IDC_CROSS;
break;
case SDL_SYSTEM_CURSOR_WAITARROW:
name = IDC_WAIT;
break;
case SDL_SYSTEM_CURSOR_SIZENWSE:
name = IDC_SIZENWSE;
break;
case SDL_SYSTEM_CURSOR_SIZENESW:
name = IDC_SIZENESW;
break;
case SDL_SYSTEM_CURSOR_SIZEWE:
name = IDC_SIZEWE;
break;
case SDL_SYSTEM_CURSOR_SIZENS:
name = IDC_SIZENS;
break;
case SDL_SYSTEM_CURSOR_SIZEALL:
name = IDC_SIZEALL;
break;
case SDL_SYSTEM_CURSOR_NO:
name = IDC_NO;
break;
case SDL_SYSTEM_CURSOR_HAND:
name = IDC_HAND;
break;
}
cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
HICON hicon;
hicon = LoadCursor(NULL, name);
cursor->driverdata = hicon;
} else {
SDL_OutOfMemory();
}
return cursor;
}
static void WIN_FreeCursor(SDL_Cursor *cursor)
{
HICON hicon = (HICON)cursor->driverdata;
DestroyIcon(hicon);
SDL_free(cursor);
}
static int WIN_ShowCursor(SDL_Cursor *cursor)
{
if (cursor == NULL) {
cursor = SDL_blank_cursor;
}
if (cursor) {
SDL_cursor = (HCURSOR)cursor->driverdata;
} else {
SDL_cursor = NULL;
}
if (SDL_GetMouseFocus() != NULL) {
SetCursor(SDL_cursor);
}
return 0;
}
void WIN_SetCursorPos(int x, int y)
{
/* We need to jitter the value because otherwise Windows will occasionally inexplicably ignore the SetCursorPos() or SendInput() */
SetCursorPos(x, y);
SetCursorPos(x + 1, y);
SetCursorPos(x, y);
/* Flush any mouse motion prior to or associated with this warp */
SDL_last_warp_time = GetTickCount();
if (!SDL_last_warp_time) {
SDL_last_warp_time = 1;
}
}
static int WIN_WarpMouse(SDL_Window *window, float x, float y)
{
SDL_WindowData *data = window->driverdata;
HWND hwnd = data->hwnd;
POINT pt;
/* Don't warp the mouse while we're doing a modal interaction */
if (data->in_title_click || data->focus_click_pending) {
return 0;
}
pt.x = (int)SDL_roundf(x);
pt.y = (int)SDL_roundf(y);
ClientToScreen(hwnd, &pt);
WIN_SetCursorPos(pt.x, pt.y);
/* Send the exact mouse motion associated with this warp */
SDL_SendMouseMotion(0, window, SDL_GetMouse()->mouseID, 0, x, y);
return 0;
}
static int WIN_WarpMouseGlobal(float x, float y)
{
POINT pt;
pt.x = (int)SDL_roundf(x);
pt.y = (int)SDL_roundf(y);
SetCursorPos(pt.x, pt.y);
return 0;
}
static int WIN_SetRelativeMouseMode(SDL_bool enabled)
{
return ToggleRawInput(enabled);
}
static int WIN_CaptureMouse(SDL_Window *window)
{
if (window) {
SDL_WindowData *data = window->driverdata;
SetCapture(data->hwnd);
} else {
SDL_Window *focus_window = SDL_GetMouseFocus();
if (focus_window) {
SDL_WindowData *data = focus_window->driverdata;
if (!data->mouse_tracked) {
SDL_SetMouseFocus(NULL);
}
}
ReleaseCapture();
}
return 0;
}
static Uint32 WIN_GetGlobalMouseState(float *x, float *y)
{
Uint32 retval = 0;
POINT pt = { 0, 0 };
SDL_bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0;
GetCursorPos(&pt);
*x = (float)pt.x;
*y = (float)pt.y;
retval |= GetAsyncKeyState(!swapButtons ? VK_LBUTTON : VK_RBUTTON) & 0x8000 ? SDL_BUTTON_LMASK : 0;
retval |= GetAsyncKeyState(!swapButtons ? VK_RBUTTON : VK_LBUTTON) & 0x8000 ? SDL_BUTTON_RMASK : 0;
retval |= GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_BUTTON_MMASK : 0;
retval |= GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_BUTTON_X1MASK : 0;
retval |= GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_BUTTON_X2MASK : 0;
return retval;
}
void WIN_InitMouse(SDL_VideoDevice *_this)
{
SDL_Mouse *mouse = SDL_GetMouse();
mouse->CreateCursor = WIN_CreateCursor;
mouse->CreateSystemCursor = WIN_CreateSystemCursor;
mouse->ShowCursor = WIN_ShowCursor;
mouse->FreeCursor = WIN_FreeCursor;
mouse->WarpMouse = WIN_WarpMouse;
mouse->WarpMouseGlobal = WIN_WarpMouseGlobal;
mouse->SetRelativeMouseMode = WIN_SetRelativeMouseMode;
mouse->CaptureMouse = WIN_CaptureMouse;
mouse->GetGlobalMouseState = WIN_GetGlobalMouseState;
SDL_SetDefaultCursor(WIN_CreateDefaultCursor());
SDL_blank_cursor = WIN_CreateBlankCursor();
WIN_UpdateMouseSystemScale();
}
void WIN_QuitMouse(SDL_VideoDevice *_this)
{
if (rawInputEnableCount) { /* force RAWINPUT off here. */
rawInputEnableCount = 1;
ToggleRawInput(SDL_FALSE);
}
if (SDL_blank_cursor) {
WIN_FreeCursor(SDL_blank_cursor);
SDL_blank_cursor = NULL;
}
}
/* For a great description of how the enhanced mouse curve works, see:
* https://superuser.com/questions/278362/windows-mouse-acceleration-curve-smoothmousexcurve-and-smoothmouseycurve
* http://www.esreality.com/?a=post&id=1846538/
*/
static SDL_bool LoadFiveFixedPointFloats(const BYTE *bytes, float *values)
{
int i;
for (i = 0; i < 5; ++i) {
float fraction = (float)((Uint16)bytes[1] << 8 | bytes[0]) / 65535.0f;
float value = (float)(((Uint16)bytes[3] << 8) | bytes[2]) + fraction;
*values++ = value;
bytes += 8;
}
return SDL_TRUE;
}
static void WIN_SetEnhancedMouseScale(int mouse_speed)
{
float scale = (float)mouse_speed / 10.0f;
HKEY hKey;
DWORD dwType = REG_BINARY;
BYTE value[40];
DWORD length = sizeof(value);
int i;
float xpoints[5];
float ypoints[5];
float scale_points[10];
const int dpi = 96; // FIXME, how do we handle different monitors with different DPI?
const float display_factor = 3.5f * (150.0f / dpi);
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Control Panel\\Mouse", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
if (RegQueryValueExW(hKey, L"SmoothMouseXCurve", 0, &dwType, value, &length) == ERROR_SUCCESS &&
LoadFiveFixedPointFloats(value, xpoints) &&
RegQueryValueExW(hKey, L"SmoothMouseYCurve", 0, &dwType, value, &length) == ERROR_SUCCESS &&
LoadFiveFixedPointFloats(value, ypoints)) {
for (i = 0; i < 5; ++i) {
float gain;
if (xpoints[i] > 0.0f) {
gain = (ypoints[i] / xpoints[i]) * scale;
} else {
gain = 0.0f;
}
scale_points[i * 2] = xpoints[i];
scale_points[i * 2 + 1] = gain / display_factor;
// SDL_Log("Point %d = %f,%f\n", i, scale_points[i * 2], scale_points[i * 2 + 1]);
}
SDL_SetMouseSystemScale(SDL_arraysize(scale_points), scale_points);
}
RegCloseKey(hKey);
}
}
static void WIN_SetLinearMouseScale(int mouse_speed)
{
static float mouse_speed_scale[] = {
0.0f,
1 / 32.0f,
1 / 16.0f,
1 / 8.0f,
2 / 8.0f,
3 / 8.0f,
4 / 8.0f,
5 / 8.0f,
6 / 8.0f,
7 / 8.0f,
1.0f,
1.25f,
1.5f,
1.75f,
2.0f,
2.25f,
2.5f,
2.75f,
3.0f,
3.25f,
3.5f
};
if (mouse_speed > 0 && mouse_speed < SDL_arraysize(mouse_speed_scale)) {
SDL_SetMouseSystemScale(1, &mouse_speed_scale[mouse_speed]);
}
}
void WIN_UpdateMouseSystemScale()
{
int mouse_speed;
int params[3] = { 0, 0, 0 };
if (SystemParametersInfo(SPI_GETMOUSESPEED, 0, &mouse_speed, 0) &&
SystemParametersInfo(SPI_GETMOUSE, 0, params, 0)) {
if (params[2]) {
WIN_SetEnhancedMouseScale(mouse_speed);
} else {
WIN_SetLinearMouseScale(mouse_speed);
}
}
}
#endif /* SDL_VIDEO_DRIVER_WINDOWS */

View File

@ -0,0 +1,34 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_windowsmouse_h_
#define SDL_windowsmouse_h_
extern DWORD SDL_last_warp_time;
extern HCURSOR SDL_cursor;
extern void WIN_InitMouse(SDL_VideoDevice *_this);
extern void WIN_QuitMouse(SDL_VideoDevice *_this);
extern void WIN_SetCursorPos(int x, int y);
extern void WIN_UpdateMouseSystemScale();
#endif /* SDL_windowsmouse_h_ */

View File

@ -0,0 +1,916 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_WINDOWS
#include "SDL_windowsvideo.h"
#include "SDL_windowsopengles.h"
/* WGL implementation of SDL OpenGL support */
#ifdef SDL_VIDEO_OPENGL_WGL
#include <SDL3/SDL_opengl.h>
#define DEFAULT_OPENGL "OPENGL32.DLL"
#ifndef WGL_ARB_create_context
#define WGL_ARB_create_context
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
#define WGL_CONTEXT_FLAGS_ARB 0x2094
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
#ifndef WGL_ARB_create_context_profile
#define WGL_ARB_create_context_profile
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
#endif
#ifndef WGL_ARB_create_context_robustness
#define WGL_ARB_create_context_robustness
#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261
#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
#endif
#endif
#ifndef WGL_EXT_create_context_es2_profile
#define WGL_EXT_create_context_es2_profile
#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
#endif
#ifndef WGL_EXT_create_context_es_profile
#define WGL_EXT_create_context_es_profile
#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004
#endif
#ifndef WGL_ARB_framebuffer_sRGB
#define WGL_ARB_framebuffer_sRGB
#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9
#endif
#ifndef WGL_ARB_pixel_format_float
#define WGL_ARB_pixel_format_float
#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0
#endif
#ifndef WGL_ARB_context_flush_control
#define WGL_ARB_context_flush_control
#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0x0000
#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
#endif
#ifndef WGL_ARB_create_context_no_error
#define WGL_ARB_create_context_no_error
#define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31B3
#endif
typedef HGLRC(APIENTRYP PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hDC,
HGLRC
hShareContext,
const int
*attribList);
#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
#define GetDC(hwnd) (HDC) hwnd
#define ReleaseDC(hwnd, hdc) 1
#define SwapBuffers _this->gl_data->wglSwapBuffers
#define DescribePixelFormat _this->gl_data->wglDescribePixelFormat
#define ChoosePixelFormat _this->gl_data->wglChoosePixelFormat
#define GetPixelFormat _this->gl_data->wglGetPixelFormat
#define SetPixelFormat _this->gl_data->wglSetPixelFormat
#endif
int WIN_GL_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
void *handle;
if (path == NULL) {
path = SDL_getenv("SDL_OPENGL_LIBRARY");
}
if (path == NULL) {
path = DEFAULT_OPENGL;
}
_this->gl_config.dll_handle = SDL_LoadObject(path);
if (!_this->gl_config.dll_handle) {
return -1;
}
SDL_strlcpy(_this->gl_config.driver_path, path,
SDL_arraysize(_this->gl_config.driver_path));
/* Allocate OpenGL memory */
_this->gl_data = (struct SDL_GLDriverData *)SDL_calloc(1, sizeof(struct SDL_GLDriverData));
if (!_this->gl_data) {
return SDL_OutOfMemory();
}
/* Load function pointers */
handle = _this->gl_config.dll_handle;
/* *INDENT-OFF* */ /* clang-format off */
_this->gl_data->wglGetProcAddress = (PROC (WINAPI *)(const char *))
SDL_LoadFunction(handle, "wglGetProcAddress");
_this->gl_data->wglCreateContext = (HGLRC (WINAPI *)(HDC))
SDL_LoadFunction(handle, "wglCreateContext");
_this->gl_data->wglDeleteContext = (BOOL (WINAPI *)(HGLRC))
SDL_LoadFunction(handle, "wglDeleteContext");
_this->gl_data->wglMakeCurrent = (BOOL (WINAPI *)(HDC, HGLRC))
SDL_LoadFunction(handle, "wglMakeCurrent");
_this->gl_data->wglShareLists = (BOOL (WINAPI *)(HGLRC, HGLRC))
SDL_LoadFunction(handle, "wglShareLists");
/* *INDENT-ON* */ /* clang-format on */
#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
_this->gl_data->wglSwapBuffers = (BOOL(WINAPI *)(HDC))
SDL_LoadFunction(handle, "wglSwapBuffers");
_this->gl_data->wglDescribePixelFormat = (int(WINAPI *)(HDC, int, UINT, LPPIXELFORMATDESCRIPTOR))
SDL_LoadFunction(handle, "wglDescribePixelFormat");
_this->gl_data->wglChoosePixelFormat = (int(WINAPI *)(HDC, const PIXELFORMATDESCRIPTOR *))
SDL_LoadFunction(handle, "wglChoosePixelFormat");
_this->gl_data->wglSetPixelFormat = (BOOL(WINAPI *)(HDC, int, const PIXELFORMATDESCRIPTOR *))
SDL_LoadFunction(handle, "wglSetPixelFormat");
_this->gl_data->wglGetPixelFormat = (int(WINAPI *)(HDC hdc))
SDL_LoadFunction(handle, "wglGetPixelFormat");
#endif
if (!_this->gl_data->wglGetProcAddress ||
!_this->gl_data->wglCreateContext ||
!_this->gl_data->wglDeleteContext ||
!_this->gl_data->wglMakeCurrent
#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
|| !_this->gl_data->wglSwapBuffers ||
!_this->gl_data->wglDescribePixelFormat ||
!_this->gl_data->wglChoosePixelFormat ||
!_this->gl_data->wglGetPixelFormat ||
!_this->gl_data->wglSetPixelFormat
#endif
) {
return SDL_SetError("Could not retrieve OpenGL functions");
}
/* XXX Too sleazy? WIN_GL_InitExtensions looks for certain OpenGL
extensions via SDL_GL_DeduceMaxSupportedESProfile. This uses
SDL_GL_ExtensionSupported which in turn calls SDL_GL_GetProcAddress.
However SDL_GL_GetProcAddress will fail if the library is not
loaded; it checks for gl_config.driver_loaded > 0. To avoid this
test failing, increment driver_loaded around the call to
WIN_GLInitExtensions.
Successful loading of the library is normally indicated by
SDL_GL_LoadLibrary incrementing driver_loaded immediately after
this function returns 0 to it.
Alternatives to this are:
- moving SDL_GL_DeduceMaxSupportedESProfile to both the WIN and
X11 platforms while adding a function equivalent to
SDL_GL_ExtensionSupported but which directly calls
glGetProcAddress(). Having 3 copies of the
SDL_GL_ExtensionSupported makes this alternative unattractive.
- moving SDL_GL_DeduceMaxSupportedESProfile to a new file shared
by the WIN and X11 platforms while adding a function equivalent
to SDL_GL_ExtensionSupported. This is unattractive due to the
number of project files that will need updating, plus there
will be 2 copies of the SDL_GL_ExtensionSupported code.
- Add a private equivalent of SDL_GL_ExtensionSupported to
SDL_video.c.
- Move the call to WIN_GL_InitExtensions back to WIN_CreateWindow
and add a flag to gl_data to avoid multiple calls to this
expensive function. This is probably the least objectionable
alternative if this increment/decrement trick is unacceptable.
Note that the driver_loaded > 0 check needs to remain in
SDL_GL_ExtensionSupported and SDL_GL_GetProcAddress as they are
public API functions.
*/
++_this->gl_config.driver_loaded;
WIN_GL_InitExtensions(_this);
--_this->gl_config.driver_loaded;
return 0;
}
SDL_FunctionPointer WIN_GL_GetProcAddress(SDL_VideoDevice *_this, const char *proc)
{
void *func;
/* This is to pick up extensions */
func = _this->gl_data->wglGetProcAddress(proc);
if (func == NULL) {
/* This is probably a normal GL function */
func = GetProcAddress(_this->gl_config.dll_handle, proc);
}
return func;
}
void WIN_GL_UnloadLibrary(SDL_VideoDevice *_this)
{
SDL_UnloadObject(_this->gl_config.dll_handle);
_this->gl_config.dll_handle = NULL;
/* Free OpenGL memory */
SDL_free(_this->gl_data);
_this->gl_data = NULL;
}
static void WIN_GL_SetupPixelFormat(SDL_VideoDevice *_this, PIXELFORMATDESCRIPTOR *pfd)
{
SDL_zerop(pfd);
pfd->nSize = sizeof(*pfd);
pfd->nVersion = 1;
pfd->dwFlags = (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL);
if (_this->gl_config.double_buffer) {
pfd->dwFlags |= PFD_DOUBLEBUFFER;
}
if (_this->gl_config.stereo) {
pfd->dwFlags |= PFD_STEREO;
}
pfd->iLayerType = PFD_MAIN_PLANE;
pfd->iPixelType = PFD_TYPE_RGBA;
pfd->cRedBits = (BYTE)_this->gl_config.red_size;
pfd->cGreenBits = (BYTE)_this->gl_config.green_size;
pfd->cBlueBits = (BYTE)_this->gl_config.blue_size;
pfd->cAlphaBits = (BYTE)_this->gl_config.alpha_size;
if (_this->gl_config.buffer_size) {
pfd->cColorBits = (BYTE)(_this->gl_config.buffer_size - _this->gl_config.alpha_size);
} else {
pfd->cColorBits = (pfd->cRedBits + pfd->cGreenBits + pfd->cBlueBits);
}
pfd->cAccumRedBits = (BYTE)_this->gl_config.accum_red_size;
pfd->cAccumGreenBits = (BYTE)_this->gl_config.accum_green_size;
pfd->cAccumBlueBits = (BYTE)_this->gl_config.accum_blue_size;
pfd->cAccumAlphaBits = (BYTE)_this->gl_config.accum_alpha_size;
pfd->cAccumBits =
(pfd->cAccumRedBits + pfd->cAccumGreenBits + pfd->cAccumBlueBits +
pfd->cAccumAlphaBits);
pfd->cDepthBits = (BYTE)_this->gl_config.depth_size;
pfd->cStencilBits = (BYTE)_this->gl_config.stencil_size;
}
/* Choose the closest pixel format that meets or exceeds the target.
FIXME: Should we weight any particular attribute over any other?
*/
static int WIN_GL_ChoosePixelFormat(SDL_VideoDevice *_this, HDC hdc, PIXELFORMATDESCRIPTOR *target)
{
PIXELFORMATDESCRIPTOR pfd;
int count, index, best = 0;
unsigned int dist, best_dist = ~0U;
count = DescribePixelFormat(hdc, 1, sizeof(pfd), NULL);
for (index = 1; index <= count; index++) {
if (!DescribePixelFormat(hdc, index, sizeof(pfd), &pfd)) {
continue;
}
if ((pfd.dwFlags & target->dwFlags) != target->dwFlags) {
continue;
}
if (pfd.iLayerType != target->iLayerType) {
continue;
}
if (pfd.iPixelType != target->iPixelType) {
continue;
}
dist = 0;
if (pfd.cColorBits < target->cColorBits) {
continue;
} else {
dist += (pfd.cColorBits - target->cColorBits);
}
if (pfd.cRedBits < target->cRedBits) {
continue;
} else {
dist += (pfd.cRedBits - target->cRedBits);
}
if (pfd.cGreenBits < target->cGreenBits) {
continue;
} else {
dist += (pfd.cGreenBits - target->cGreenBits);
}
if (pfd.cBlueBits < target->cBlueBits) {
continue;
} else {
dist += (pfd.cBlueBits - target->cBlueBits);
}
if (pfd.cAlphaBits < target->cAlphaBits) {
continue;
} else {
dist += (pfd.cAlphaBits - target->cAlphaBits);
}
if (pfd.cAccumBits < target->cAccumBits) {
continue;
} else {
dist += (pfd.cAccumBits - target->cAccumBits);
}
if (pfd.cAccumRedBits < target->cAccumRedBits) {
continue;
} else {
dist += (pfd.cAccumRedBits - target->cAccumRedBits);
}
if (pfd.cAccumGreenBits < target->cAccumGreenBits) {
continue;
} else {
dist += (pfd.cAccumGreenBits - target->cAccumGreenBits);
}
if (pfd.cAccumBlueBits < target->cAccumBlueBits) {
continue;
} else {
dist += (pfd.cAccumBlueBits - target->cAccumBlueBits);
}
if (pfd.cAccumAlphaBits < target->cAccumAlphaBits) {
continue;
} else {
dist += (pfd.cAccumAlphaBits - target->cAccumAlphaBits);
}
if (pfd.cDepthBits < target->cDepthBits) {
continue;
} else {
dist += (pfd.cDepthBits - target->cDepthBits);
}
if (pfd.cStencilBits < target->cStencilBits) {
continue;
} else {
dist += (pfd.cStencilBits - target->cStencilBits);
}
if (dist < best_dist) {
best = index;
best_dist = dist;
}
}
return best;
}
static SDL_bool HasExtension(const char *extension, const char *extensions)
{
const char *start;
const char *where, *terminator;
/* Extension names should not have spaces. */
where = SDL_strchr(extension, ' ');
if (where || *extension == '\0') {
return SDL_FALSE;
}
if (extensions == NULL) {
return SDL_FALSE;
}
/* It takes a bit of care to be fool-proof about parsing the
* OpenGL extensions string. Don't be fooled by sub-strings,
* etc. */
start = extensions;
for (;;) {
where = SDL_strstr(start, extension);
if (where == NULL) {
break;
}
terminator = where + SDL_strlen(extension);
if (where == start || *(where - 1) == ' ') {
if (*terminator == ' ' || *terminator == '\0') {
return SDL_TRUE;
}
}
start = terminator;
}
return SDL_FALSE;
}
void WIN_GL_InitExtensions(SDL_VideoDevice *_this)
{
/* *INDENT-OFF* */ /* clang-format off */
const char *(WINAPI * wglGetExtensionsStringARB)(HDC) = 0;
/* *INDENT-ON* */ /* clang-format on */
const char *extensions;
HWND hwnd;
HDC hdc;
HGLRC hglrc;
PIXELFORMATDESCRIPTOR pfd;
if (!_this->gl_data) {
return;
}
hwnd =
CreateWindow(SDL_Appname, SDL_Appname, (WS_POPUP | WS_DISABLED), 0, 0,
10, 10, NULL, NULL, SDL_Instance, NULL);
if (!hwnd) {
return;
}
WIN_PumpEvents(_this);
hdc = GetDC(hwnd);
WIN_GL_SetupPixelFormat(_this, &pfd);
SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pfd), &pfd);
hglrc = _this->gl_data->wglCreateContext(hdc);
if (!hglrc) {
return;
}
_this->gl_data->wglMakeCurrent(hdc, hglrc);
/* *INDENT-OFF* */ /* clang-format off */
wglGetExtensionsStringARB = (const char *(WINAPI *)(HDC))
_this->gl_data->wglGetProcAddress("wglGetExtensionsStringARB");
/* *INDENT-ON* */ /* clang-format on */
if (wglGetExtensionsStringARB) {
extensions = wglGetExtensionsStringARB(hdc);
} else {
extensions = NULL;
}
/* Check for WGL_ARB_pixel_format */
_this->gl_data->HAS_WGL_ARB_pixel_format = SDL_FALSE;
if (HasExtension("WGL_ARB_pixel_format", extensions)) {
/* *INDENT-OFF* */ /* clang-format off */
_this->gl_data->wglChoosePixelFormatARB =
(BOOL (WINAPI *)(HDC, const int *, const FLOAT *, UINT, int *, UINT *))
WIN_GL_GetProcAddress(_this, "wglChoosePixelFormatARB");
_this->gl_data->wglGetPixelFormatAttribivARB =
(BOOL (WINAPI *)(HDC, int, int, UINT, const int *, int *))
WIN_GL_GetProcAddress(_this, "wglGetPixelFormatAttribivARB");
/* *INDENT-ON* */ /* clang-format on */
if ((_this->gl_data->wglChoosePixelFormatARB != NULL) &&
(_this->gl_data->wglGetPixelFormatAttribivARB != NULL)) {
_this->gl_data->HAS_WGL_ARB_pixel_format = SDL_TRUE;
}
}
/* Check for WGL_EXT_swap_control */
_this->gl_data->HAS_WGL_EXT_swap_control_tear = SDL_FALSE;
if (HasExtension("WGL_EXT_swap_control", extensions)) {
_this->gl_data->wglSwapIntervalEXT =
(BOOL (WINAPI *)(int))
WIN_GL_GetProcAddress(_this, "wglSwapIntervalEXT");
_this->gl_data->wglGetSwapIntervalEXT =
(int (WINAPI *)(void))
WIN_GL_GetProcAddress(_this, "wglGetSwapIntervalEXT");
if (HasExtension("WGL_EXT_swap_control_tear", extensions)) {
_this->gl_data->HAS_WGL_EXT_swap_control_tear = SDL_TRUE;
}
} else {
_this->gl_data->wglSwapIntervalEXT = NULL;
_this->gl_data->wglGetSwapIntervalEXT = NULL;
}
/* Check for WGL_EXT_create_context_es2_profile */
if (HasExtension("WGL_EXT_create_context_es2_profile", extensions)) {
SDL_GL_DeduceMaxSupportedESProfile(
&_this->gl_data->es_profile_max_supported_version.major,
&_this->gl_data->es_profile_max_supported_version.minor);
}
/* Check for WGL_ARB_context_flush_control */
if (HasExtension("WGL_ARB_context_flush_control", extensions)) {
_this->gl_data->HAS_WGL_ARB_context_flush_control = SDL_TRUE;
}
/* Check for WGL_ARB_create_context_robustness */
if (HasExtension("WGL_ARB_create_context_robustness", extensions)) {
_this->gl_data->HAS_WGL_ARB_create_context_robustness = SDL_TRUE;
}
/* Check for WGL_ARB_create_context_no_error */
if (HasExtension("WGL_ARB_create_context_no_error", extensions)) {
_this->gl_data->HAS_WGL_ARB_create_context_no_error = SDL_TRUE;
}
_this->gl_data->wglMakeCurrent(hdc, NULL);
_this->gl_data->wglDeleteContext(hglrc);
ReleaseDC(hwnd, hdc);
DestroyWindow(hwnd);
WIN_PumpEvents(_this);
}
static int WIN_GL_ChoosePixelFormatARB(SDL_VideoDevice *_this, int *iAttribs, float *fAttribs)
{
HWND hwnd;
HDC hdc;
PIXELFORMATDESCRIPTOR pfd;
HGLRC hglrc;
int pixel_format = 0;
unsigned int matching;
hwnd =
CreateWindow(SDL_Appname, SDL_Appname, (WS_POPUP | WS_DISABLED), 0, 0,
10, 10, NULL, NULL, SDL_Instance, NULL);
WIN_PumpEvents(_this);
hdc = GetDC(hwnd);
WIN_GL_SetupPixelFormat(_this, &pfd);
SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pfd), &pfd);
hglrc = _this->gl_data->wglCreateContext(hdc);
if (hglrc) {
_this->gl_data->wglMakeCurrent(hdc, hglrc);
if (_this->gl_data->HAS_WGL_ARB_pixel_format) {
_this->gl_data->wglChoosePixelFormatARB(hdc, iAttribs, fAttribs,
1, &pixel_format,
&matching);
}
_this->gl_data->wglMakeCurrent(hdc, NULL);
_this->gl_data->wglDeleteContext(hglrc);
}
ReleaseDC(hwnd, hdc);
DestroyWindow(hwnd);
WIN_PumpEvents(_this);
return pixel_format;
}
/* actual work of WIN_GL_SetupWindow() happens here. */
static int WIN_GL_SetupWindowInternal(SDL_VideoDevice *_this, SDL_Window *window)
{
HDC hdc = window->driverdata->hdc;
PIXELFORMATDESCRIPTOR pfd;
int pixel_format = 0;
int iAttribs[64];
int *iAttr;
int *iAccelAttr;
float fAttribs[1] = { 0 };
WIN_GL_SetupPixelFormat(_this, &pfd);
/* setup WGL_ARB_pixel_format attribs */
iAttr = &iAttribs[0];
*iAttr++ = WGL_DRAW_TO_WINDOW_ARB;
*iAttr++ = GL_TRUE;
*iAttr++ = WGL_RED_BITS_ARB;
*iAttr++ = _this->gl_config.red_size;
*iAttr++ = WGL_GREEN_BITS_ARB;
*iAttr++ = _this->gl_config.green_size;
*iAttr++ = WGL_BLUE_BITS_ARB;
*iAttr++ = _this->gl_config.blue_size;
if (_this->gl_config.alpha_size) {
*iAttr++ = WGL_ALPHA_BITS_ARB;
*iAttr++ = _this->gl_config.alpha_size;
}
*iAttr++ = WGL_DOUBLE_BUFFER_ARB;
*iAttr++ = _this->gl_config.double_buffer;
*iAttr++ = WGL_DEPTH_BITS_ARB;
*iAttr++ = _this->gl_config.depth_size;
if (_this->gl_config.stencil_size) {
*iAttr++ = WGL_STENCIL_BITS_ARB;
*iAttr++ = _this->gl_config.stencil_size;
}
if (_this->gl_config.accum_red_size) {
*iAttr++ = WGL_ACCUM_RED_BITS_ARB;
*iAttr++ = _this->gl_config.accum_red_size;
}
if (_this->gl_config.accum_green_size) {
*iAttr++ = WGL_ACCUM_GREEN_BITS_ARB;
*iAttr++ = _this->gl_config.accum_green_size;
}
if (_this->gl_config.accum_blue_size) {
*iAttr++ = WGL_ACCUM_BLUE_BITS_ARB;
*iAttr++ = _this->gl_config.accum_blue_size;
}
if (_this->gl_config.accum_alpha_size) {
*iAttr++ = WGL_ACCUM_ALPHA_BITS_ARB;
*iAttr++ = _this->gl_config.accum_alpha_size;
}
if (_this->gl_config.stereo) {
*iAttr++ = WGL_STEREO_ARB;
*iAttr++ = GL_TRUE;
}
if (_this->gl_config.multisamplebuffers) {
*iAttr++ = WGL_SAMPLE_BUFFERS_ARB;
*iAttr++ = _this->gl_config.multisamplebuffers;
}
if (_this->gl_config.multisamplesamples) {
*iAttr++ = WGL_SAMPLES_ARB;
*iAttr++ = _this->gl_config.multisamplesamples;
}
if (_this->gl_config.floatbuffers) {
*iAttr++ = WGL_TYPE_RGBA_FLOAT_ARB;
}
if (_this->gl_config.framebuffer_srgb_capable) {
*iAttr++ = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
*iAttr++ = _this->gl_config.framebuffer_srgb_capable;
}
/* We always choose either FULL or NO accel on Windows, because of flaky
drivers. If the app didn't specify, we use FULL, because that's
probably what they wanted (and if you didn't care and got FULL, that's
a perfectly valid result in any case). */
*iAttr++ = WGL_ACCELERATION_ARB;
iAccelAttr = iAttr;
if (_this->gl_config.accelerated) {
*iAttr++ = WGL_FULL_ACCELERATION_ARB;
} else {
*iAttr++ = WGL_NO_ACCELERATION_ARB;
}
*iAttr = 0;
/* Choose and set the closest available pixel format */
pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs);
/* App said "don't care about accel" and FULL accel failed. Try NO. */
if ((!pixel_format) && (_this->gl_config.accelerated < 0)) {
*iAccelAttr = WGL_NO_ACCELERATION_ARB;
pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs);
*iAccelAttr = WGL_FULL_ACCELERATION_ARB; /* if we try again. */
}
if (!pixel_format) {
pixel_format = WIN_GL_ChoosePixelFormat(_this, hdc, &pfd);
}
if (!pixel_format) {
return SDL_SetError("No matching GL pixel format available");
}
if (!SetPixelFormat(hdc, pixel_format, &pfd)) {
return WIN_SetError("SetPixelFormat()");
}
return 0;
}
int WIN_GL_SetupWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
/* The current context is lost in here; save it and reset it. */
SDL_Window *current_win = SDL_GL_GetCurrentWindow();
SDL_GLContext current_ctx = SDL_GL_GetCurrentContext();
const int retval = WIN_GL_SetupWindowInternal(_this, window);
WIN_GL_MakeCurrent(_this, current_win, current_ctx);
return retval;
}
SDL_bool WIN_GL_UseEGL(SDL_VideoDevice *_this)
{
SDL_assert(_this->gl_data != NULL);
SDL_assert(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES);
return SDL_GetHintBoolean(SDL_HINT_OPENGL_ES_DRIVER, SDL_FALSE) || _this->gl_config.major_version == 1 || _this->gl_config.major_version > _this->gl_data->es_profile_max_supported_version.major || (_this->gl_config.major_version == _this->gl_data->es_profile_max_supported_version.major && _this->gl_config.minor_version > _this->gl_data->es_profile_max_supported_version.minor); /* No WGL extension for OpenGL ES 1.x profiles. */
}
SDL_GLContext WIN_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window)
{
HDC hdc = window->driverdata->hdc;
HGLRC context, share_context;
if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES && WIN_GL_UseEGL(_this)) {
#ifdef SDL_VIDEO_OPENGL_EGL
/* Switch to EGL based functions */
WIN_GL_UnloadLibrary(_this);
_this->GL_LoadLibrary = WIN_GLES_LoadLibrary;
_this->GL_GetProcAddress = WIN_GLES_GetProcAddress;
_this->GL_UnloadLibrary = WIN_GLES_UnloadLibrary;
_this->GL_CreateContext = WIN_GLES_CreateContext;
_this->GL_MakeCurrent = WIN_GLES_MakeCurrent;
_this->GL_SetSwapInterval = WIN_GLES_SetSwapInterval;
_this->GL_GetSwapInterval = WIN_GLES_GetSwapInterval;
_this->GL_SwapWindow = WIN_GLES_SwapWindow;
_this->GL_DeleteContext = WIN_GLES_DeleteContext;
_this->GL_GetEGLSurface = WIN_GLES_GetEGLSurface;
if (WIN_GLES_LoadLibrary(_this, NULL) != 0) {
return NULL;
}
return WIN_GLES_CreateContext(_this, window);
#else
SDL_SetError("SDL not configured with EGL support");
return NULL;
#endif
}
if (_this->gl_config.share_with_current_context) {
share_context = (HGLRC)SDL_GL_GetCurrentContext();
} else {
share_context = 0;
}
if (_this->gl_config.major_version < 3 &&
_this->gl_config.profile_mask == 0 &&
_this->gl_config.flags == 0) {
/* Create legacy context */
context = _this->gl_data->wglCreateContext(hdc);
if (share_context != 0) {
_this->gl_data->wglShareLists(share_context, context);
}
} else {
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
HGLRC temp_context = _this->gl_data->wglCreateContext(hdc);
if (!temp_context) {
SDL_SetError("Could not create GL context");
return NULL;
}
/* Make the context current */
if (WIN_GL_MakeCurrent(_this, window, temp_context) < 0) {
WIN_GL_DeleteContext(_this, temp_context);
return NULL;
}
wglCreateContextAttribsARB =
(PFNWGLCREATECONTEXTATTRIBSARBPROC)_this->gl_data->wglGetProcAddress("wglCreateContextAttribsARB");
if (!wglCreateContextAttribsARB) {
SDL_SetError("GL 3.x is not supported");
context = temp_context;
} else {
int attribs[15]; /* max 14 attributes plus terminator */
int iattr = 0;
attribs[iattr++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
attribs[iattr++] = _this->gl_config.major_version;
attribs[iattr++] = WGL_CONTEXT_MINOR_VERSION_ARB;
attribs[iattr++] = _this->gl_config.minor_version;
/* SDL profile bits match WGL profile bits */
if (_this->gl_config.profile_mask != 0) {
attribs[iattr++] = WGL_CONTEXT_PROFILE_MASK_ARB;
attribs[iattr++] = _this->gl_config.profile_mask;
}
/* SDL flags match WGL flags */
if (_this->gl_config.flags != 0) {
attribs[iattr++] = WGL_CONTEXT_FLAGS_ARB;
attribs[iattr++] = _this->gl_config.flags;
}
/* only set if wgl extension is available and not the default setting */
if ((_this->gl_data->HAS_WGL_ARB_context_flush_control) && (_this->gl_config.release_behavior == 0)) {
attribs[iattr++] = WGL_CONTEXT_RELEASE_BEHAVIOR_ARB;
attribs[iattr++] = _this->gl_config.release_behavior ? WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB : WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB;
}
/* only set if wgl extension is available and not the default setting */
if ((_this->gl_data->HAS_WGL_ARB_create_context_robustness) && (_this->gl_config.reset_notification != 0)) {
attribs[iattr++] = WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB;
attribs[iattr++] = _this->gl_config.reset_notification ? WGL_LOSE_CONTEXT_ON_RESET_ARB : WGL_NO_RESET_NOTIFICATION_ARB;
}
/* only set if wgl extension is available and not the default setting */
if ((_this->gl_data->HAS_WGL_ARB_create_context_no_error) && (_this->gl_config.no_error != 0)) {
attribs[iattr++] = WGL_CONTEXT_OPENGL_NO_ERROR_ARB;
attribs[iattr++] = _this->gl_config.no_error;
}
attribs[iattr++] = 0;
/* Create the GL 3.x context */
context = wglCreateContextAttribsARB(hdc, share_context, attribs);
/* Delete the GL 2.x context */
_this->gl_data->wglDeleteContext(temp_context);
}
}
if (!context) {
WIN_SetError("Could not create GL context");
return NULL;
}
if (WIN_GL_MakeCurrent(_this, window, context) < 0) {
WIN_GL_DeleteContext(_this, context);
return NULL;
}
return context;
}
int WIN_GL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context)
{
HDC hdc;
if (!_this->gl_data) {
return SDL_SetError("OpenGL not initialized");
}
/* sanity check that higher level handled this. */
SDL_assert(window || (window == NULL && !context));
/* Some Windows drivers freak out if hdc is NULL, even when context is
NULL, against spec. Since hdc is _supposed_ to be ignored if context
is NULL, we either use the current GL window, or do nothing if we
already have no current context. */
if (window == NULL) {
window = SDL_GL_GetCurrentWindow();
if (window == NULL) {
SDL_assert(SDL_GL_GetCurrentContext() == NULL);
return 0; /* already done. */
}
}
hdc = window->driverdata->hdc;
if (!_this->gl_data->wglMakeCurrent(hdc, (HGLRC)context)) {
return WIN_SetError("wglMakeCurrent()");
}
return 0;
}
int WIN_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval)
{
if ((interval < 0) && (!_this->gl_data->HAS_WGL_EXT_swap_control_tear)) {
return SDL_SetError("Negative swap interval unsupported in this GL");
} else if (_this->gl_data->wglSwapIntervalEXT) {
if (_this->gl_data->wglSwapIntervalEXT(interval) != TRUE) {
return WIN_SetError("wglSwapIntervalEXT()");
}
} else {
return SDL_Unsupported();
}
return 0;
}
int WIN_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval)
{
if (_this->gl_data->wglGetSwapIntervalEXT) {
*interval = _this->gl_data->wglGetSwapIntervalEXT();
return 0;
} else {
return -1;
}
}
int WIN_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
HDC hdc = window->driverdata->hdc;
if (!SwapBuffers(hdc)) {
return WIN_SetError("SwapBuffers()");
}
return 0;
}
int WIN_GL_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context)
{
if (!_this->gl_data) {
return 0;
}
_this->gl_data->wglDeleteContext((HGLRC)context);
return 0;
}
SDL_bool WIN_GL_SetPixelFormatFrom(SDL_VideoDevice *_this, SDL_Window *fromWindow, SDL_Window *toWindow)
{
HDC hfromdc = fromWindow->driverdata->hdc;
HDC htodc = toWindow->driverdata->hdc;
BOOL result;
/* get the pixel format of the fromWindow */
int pixel_format = GetPixelFormat(hfromdc);
PIXELFORMATDESCRIPTOR pfd;
SDL_memset(&pfd, 0, sizeof(pfd));
DescribePixelFormat(hfromdc, pixel_format, sizeof(pfd), &pfd);
/* set the pixel format of the toWindow */
result = SetPixelFormat(htodc, pixel_format, &pfd);
return result ? SDL_TRUE : SDL_FALSE;
}
#endif /* SDL_VIDEO_OPENGL_WGL */
#endif /* SDL_VIDEO_DRIVER_WINDOWS */

View File

@ -0,0 +1,179 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_windowsopengl_h_
#define SDL_windowsopengl_h_
#ifdef SDL_VIDEO_OPENGL_WGL
#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
typedef struct tagPIXELFORMATDESCRIPTOR
{
WORD nSize;
WORD nVersion;
DWORD dwFlags;
BYTE iPixelType;
BYTE cColorBits;
BYTE cRedBits;
BYTE cRedShift;
BYTE cGreenBits;
BYTE cGreenShift;
BYTE cBlueBits;
BYTE cBlueShift;
BYTE cAlphaBits;
BYTE cAlphaShift;
BYTE cAccumBits;
BYTE cAccumRedBits;
BYTE cAccumGreenBits;
BYTE cAccumBlueBits;
BYTE cAccumAlphaBits;
BYTE cDepthBits;
BYTE cStencilBits;
BYTE cAuxBuffers;
BYTE iLayerType;
BYTE bReserved;
DWORD dwLayerMask;
DWORD dwVisibleMask;
DWORD dwDamageMask;
} PIXELFORMATDESCRIPTOR, *PPIXELFORMATDESCRIPTOR, *LPPIXELFORMATDESCRIPTOR;
#endif
struct SDL_GLDriverData
{
SDL_bool HAS_WGL_ARB_pixel_format;
SDL_bool HAS_WGL_EXT_swap_control_tear;
SDL_bool HAS_WGL_ARB_context_flush_control;
SDL_bool HAS_WGL_ARB_create_context_robustness;
SDL_bool HAS_WGL_ARB_create_context_no_error;
/* Max version of OpenGL ES context that can be created if the
implementation supports WGL_EXT_create_context_es2_profile.
major = minor = 0 when unsupported.
*/
struct
{
int major;
int minor;
} es_profile_max_supported_version;
/* *INDENT-OFF* */ /* clang-format off */
PROC (WINAPI *wglGetProcAddress)(const char *proc);
HGLRC (WINAPI *wglCreateContext)(HDC hdc);
BOOL (WINAPI *wglDeleteContext)(HGLRC hglrc);
BOOL (WINAPI *wglMakeCurrent)(HDC hdc, HGLRC hglrc);
BOOL (WINAPI *wglShareLists)(HGLRC hglrc1, HGLRC hglrc2);
BOOL (WINAPI *wglChoosePixelFormatARB)(HDC hdc, const int *piAttribIList, const FLOAT * pfAttribFList, UINT nMaxFormats, int *piFormats, UINT * nNumFormats);
BOOL (WINAPI *wglGetPixelFormatAttribivARB)(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);
BOOL (WINAPI *wglSwapIntervalEXT)(int interval);
int (WINAPI *wglGetSwapIntervalEXT)(void);
#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
BOOL (WINAPI *wglSwapBuffers)(HDC hdc);
int (WINAPI *wglDescribePixelFormat)(HDC hdc,
int iPixelFormat,
UINT nBytes,
LPPIXELFORMATDESCRIPTOR ppfd);
int (WINAPI *wglChoosePixelFormat)(HDC hdc,
const PIXELFORMATDESCRIPTOR *ppfd);
BOOL (WINAPI *wglSetPixelFormat)(HDC hdc,
int format,
const PIXELFORMATDESCRIPTOR *ppfd);
int (WINAPI *wglGetPixelFormat)(HDC hdc);
#endif
/* *INDENT-ON* */ /* clang-format on */
};
/* OpenGL functions */
extern int WIN_GL_LoadLibrary(SDL_VideoDevice *_this, const char *path);
extern SDL_FunctionPointer WIN_GL_GetProcAddress(SDL_VideoDevice *_this, const char *proc);
extern void WIN_GL_UnloadLibrary(SDL_VideoDevice *_this);
extern SDL_bool WIN_GL_UseEGL(SDL_VideoDevice *_this);
extern int WIN_GL_SetupWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern SDL_GLContext WIN_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
extern int WIN_GL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window,
SDL_GLContext context);
extern int WIN_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval);
extern int WIN_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval);
extern int WIN_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int WIN_GL_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context);
extern void WIN_GL_InitExtensions(SDL_VideoDevice *_this);
extern SDL_bool WIN_GL_SetPixelFormatFrom(SDL_VideoDevice *_this, SDL_Window *fromWindow, SDL_Window *toWindow);
#ifndef WGL_ARB_pixel_format
#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
#define WGL_DRAW_TO_BITMAP_ARB 0x2002
#define WGL_ACCELERATION_ARB 0x2003
#define WGL_NEED_PALETTE_ARB 0x2004
#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
#define WGL_SWAP_METHOD_ARB 0x2007
#define WGL_NUMBER_OVERLAYS_ARB 0x2008
#define WGL_NUMBER_UNDERLAYS_ARB 0x2009
#define WGL_TRANSPARENT_ARB 0x200A
#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
#define WGL_SHARE_DEPTH_ARB 0x200C
#define WGL_SHARE_STENCIL_ARB 0x200D
#define WGL_SHARE_ACCUM_ARB 0x200E
#define WGL_SUPPORT_GDI_ARB 0x200F
#define WGL_SUPPORT_OPENGL_ARB 0x2010
#define WGL_DOUBLE_BUFFER_ARB 0x2011
#define WGL_STEREO_ARB 0x2012
#define WGL_PIXEL_TYPE_ARB 0x2013
#define WGL_COLOR_BITS_ARB 0x2014
#define WGL_RED_BITS_ARB 0x2015
#define WGL_RED_SHIFT_ARB 0x2016
#define WGL_GREEN_BITS_ARB 0x2017
#define WGL_GREEN_SHIFT_ARB 0x2018
#define WGL_BLUE_BITS_ARB 0x2019
#define WGL_BLUE_SHIFT_ARB 0x201A
#define WGL_ALPHA_BITS_ARB 0x201B
#define WGL_ALPHA_SHIFT_ARB 0x201C
#define WGL_ACCUM_BITS_ARB 0x201D
#define WGL_ACCUM_RED_BITS_ARB 0x201E
#define WGL_ACCUM_GREEN_BITS_ARB 0x201F
#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
#define WGL_DEPTH_BITS_ARB 0x2022
#define WGL_STENCIL_BITS_ARB 0x2023
#define WGL_AUX_BUFFERS_ARB 0x2024
#define WGL_NO_ACCELERATION_ARB 0x2025
#define WGL_GENERIC_ACCELERATION_ARB 0x2026
#define WGL_FULL_ACCELERATION_ARB 0x2027
#define WGL_SWAP_EXCHANGE_ARB 0x2028
#define WGL_SWAP_COPY_ARB 0x2029
#define WGL_SWAP_UNDEFINED_ARB 0x202A
#define WGL_TYPE_RGBA_ARB 0x202B
#define WGL_TYPE_COLORINDEX_ARB 0x202C
#endif
#ifndef WGL_ARB_multisample
#define WGL_SAMPLE_BUFFERS_ARB 0x2041
#define WGL_SAMPLES_ARB 0x2042
#endif
#endif /* SDL_VIDEO_OPENGL_WGL */
#endif /* SDL_windowsopengl_h_ */

View File

@ -0,0 +1,144 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_DRIVER_WINDOWS) && defined(SDL_VIDEO_OPENGL_EGL) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
#include "SDL_windowsvideo.h"
#include "SDL_windowsopengles.h"
#include "SDL_windowsopengl.h"
#include "SDL_windowswindow.h"
/* EGL implementation of SDL OpenGL support */
int WIN_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
/* If the profile requested is not GL ES, switch over to WIN_GL functions */
if (_this->gl_config.profile_mask != SDL_GL_CONTEXT_PROFILE_ES &&
!SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, SDL_FALSE)) {
#ifdef SDL_VIDEO_OPENGL_WGL
WIN_GLES_UnloadLibrary(_this);
_this->GL_LoadLibrary = WIN_GL_LoadLibrary;
_this->GL_GetProcAddress = WIN_GL_GetProcAddress;
_this->GL_UnloadLibrary = WIN_GL_UnloadLibrary;
_this->GL_CreateContext = WIN_GL_CreateContext;
_this->GL_MakeCurrent = WIN_GL_MakeCurrent;
_this->GL_SetSwapInterval = WIN_GL_SetSwapInterval;
_this->GL_GetSwapInterval = WIN_GL_GetSwapInterval;
_this->GL_SwapWindow = WIN_GL_SwapWindow;
_this->GL_DeleteContext = WIN_GL_DeleteContext;
_this->GL_GetEGLSurface = NULL;
return WIN_GL_LoadLibrary(_this, path);
#else
return SDL_SetError("SDL not configured with OpenGL/WGL support");
#endif
}
if (_this->egl_data == NULL) {
return SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY, _this->gl_config.egl_platform);
}
return 0;
}
SDL_GLContext WIN_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_GLContext context;
SDL_WindowData *data = window->driverdata;
#ifdef SDL_VIDEO_OPENGL_WGL
if (_this->gl_config.profile_mask != SDL_GL_CONTEXT_PROFILE_ES &&
!SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, SDL_FALSE)) {
/* Switch to WGL based functions */
WIN_GLES_UnloadLibrary(_this);
_this->GL_LoadLibrary = WIN_GL_LoadLibrary;
_this->GL_GetProcAddress = WIN_GL_GetProcAddress;
_this->GL_UnloadLibrary = WIN_GL_UnloadLibrary;
_this->GL_CreateContext = WIN_GL_CreateContext;
_this->GL_MakeCurrent = WIN_GL_MakeCurrent;
_this->GL_SetSwapInterval = WIN_GL_SetSwapInterval;
_this->GL_GetSwapInterval = WIN_GL_GetSwapInterval;
_this->GL_SwapWindow = WIN_GL_SwapWindow;
_this->GL_DeleteContext = WIN_GL_DeleteContext;
_this->GL_GetEGLSurface = NULL;
if (WIN_GL_LoadLibrary(_this, NULL) != 0) {
return NULL;
}
return WIN_GL_CreateContext(_this, window);
}
#endif
context = SDL_EGL_CreateContext(_this, data->egl_surface);
return context;
}
int WIN_GLES_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context)
{
SDL_EGL_DeleteContext(_this, context);
return 0;
}
/* *INDENT-OFF* */ /* clang-format off */
SDL_EGL_SwapWindow_impl(WIN)
SDL_EGL_MakeCurrent_impl(WIN)
/* *INDENT-ON* */ /* clang-format on */
int WIN_GLES_SetupWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
/* The current context is lost in here; save it and reset it. */
SDL_WindowData *windowdata = window->driverdata;
SDL_Window *current_win = SDL_GL_GetCurrentWindow();
SDL_GLContext current_ctx = SDL_GL_GetCurrentContext();
if (_this->egl_data == NULL) {
/* !!! FIXME: commenting out this assertion is (I think) incorrect; figure out why driver_loaded is wrong for ANGLE instead. --ryan. */
#if 0 /* When hint SDL_HINT_OPENGL_ES_DRIVER is set to "1" (e.g. for ANGLE support), _this->gl_config.driver_loaded can be 1, while the below lines function. */
SDL_assert(!_this->gl_config.driver_loaded);
#endif
if (SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY, _this->gl_config.egl_platform) < 0) {
SDL_EGL_UnloadLibrary(_this);
return -1;
}
_this->gl_config.driver_loaded = 1;
}
/* Create the GLES window surface */
windowdata->egl_surface = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)windowdata->hwnd);
if (windowdata->egl_surface == EGL_NO_SURFACE) {
return SDL_SetError("Could not create GLES window surface");
}
return WIN_GLES_MakeCurrent(_this, current_win, current_ctx);
}
EGLSurface
WIN_GLES_GetEGLSurface(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *windowdata = window->driverdata;
return windowdata->egl_surface;
}
#endif /* SDL_VIDEO_DRIVER_WINDOWS && SDL_VIDEO_OPENGL_EGL */

View File

@ -0,0 +1,48 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_winopengles_h_
#define SDL_winopengles_h_
#ifdef SDL_VIDEO_OPENGL_EGL
#include "../SDL_sysvideo.h"
#include "../SDL_egl_c.h"
/* OpenGLES functions */
#define WIN_GLES_GetAttribute SDL_EGL_GetAttribute
#define WIN_GLES_GetProcAddress SDL_EGL_GetProcAddressInternal
#define WIN_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
#define WIN_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
#define WIN_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
extern int WIN_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path);
extern SDL_GLContext WIN_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
extern int WIN_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int WIN_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
extern int WIN_GLES_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context);
extern int WIN_GLES_SetupWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern SDL_EGLSurface WIN_GLES_GetEGLSurface(SDL_VideoDevice *_this, SDL_Window *window);
#endif /* SDL_VIDEO_OPENGL_EGL */
#endif /* SDL_winopengles_h_ */

View File

@ -0,0 +1,90 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_DRIVER_WINDOWS) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
#include "SDL_windowsshape.h"
#include "SDL_windowsvideo.h"
SDL_WindowShaper *Win32_CreateShaper(SDL_Window *window)
{
SDL_WindowShaper *result = (SDL_WindowShaper *)SDL_malloc(sizeof(SDL_WindowShaper));
if (result == NULL) {
SDL_OutOfMemory();
return NULL;
}
result->window = window;
result->mode.mode = ShapeModeDefault;
result->mode.parameters.binarizationCutoff = 1;
result->hasshape = SDL_FALSE;
result->driverdata = (SDL_ShapeData *)SDL_calloc(1, sizeof(SDL_ShapeData));
if (!result->driverdata) {
SDL_free(result);
SDL_OutOfMemory();
return NULL;
}
window->shaper = result;
return result;
}
static void CombineRectRegions(SDL_ShapeTree *node, void *closure)
{
HRGN mask_region = *((HRGN *)closure), temp_region = NULL;
if (node->kind == OpaqueShape) {
/* Win32 API regions exclude their outline, so we widen the region by one pixel in each direction to include the real outline. */
temp_region = CreateRectRgn(node->data.shape.x, node->data.shape.y, node->data.shape.x + node->data.shape.w + 1, node->data.shape.y + node->data.shape.h + 1);
if (mask_region != NULL) {
CombineRgn(mask_region, mask_region, temp_region, RGN_OR);
DeleteObject(temp_region);
} else {
*((HRGN *)closure) = temp_region;
}
}
}
int Win32_SetWindowShape(SDL_WindowShaper *shaper, SDL_Surface *shape, SDL_WindowShapeMode *shape_mode)
{
SDL_ShapeData *data;
HRGN mask_region = NULL;
if ((shaper == NULL) ||
(shape == NULL) ||
((shape->format->Amask == 0) && (shape_mode->mode != ShapeModeColorKey))) {
return SDL_INVALID_SHAPE_ARGUMENT;
}
data = (SDL_ShapeData *)shaper->driverdata;
if (data->mask_tree != NULL) {
SDL_FreeShapeTree(&data->mask_tree);
}
data->mask_tree = SDL_CalculateShapeTree(*shape_mode, shape);
SDL_TraverseShapeTree(data->mask_tree, &CombineRectRegions, &mask_region);
SDL_assert(mask_region != NULL);
SetWindowRgn(shaper->window->driverdata->hwnd, mask_region, TRUE);
return 0;
}
#endif /* SDL_VIDEO_DRIVER_WINDOWS */

View File

@ -0,0 +1,38 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_windowsshape_h_
#define SDL_windowsshape_h_
#include "../SDL_sysvideo.h"
#include "../SDL_shape_internals.h"
typedef struct
{
SDL_ShapeTree *mask_tree;
} SDL_ShapeData;
extern SDL_WindowShaper *Win32_CreateShaper(SDL_Window *window);
extern int Win32_SetWindowShape(SDL_WindowShaper *shaper, SDL_Surface *shape, SDL_WindowShapeMode *shape_mode);
#endif /* SDL_windowsshape_h_ */

View File

@ -0,0 +1,722 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_WINDOWS
#include "../SDL_sysvideo.h"
#include "../SDL_pixels_c.h"
#include "../../SDL_hints_c.h"
#include "SDL_windowsvideo.h"
#include "SDL_windowsframebuffer.h"
#include "SDL_windowsshape.h"
#include "SDL_windowsvulkan.h"
#ifdef SDL_GDK_TEXTINPUT
#include "../gdk/SDL_gdktextinput.h"
#endif
/* #define HIGHDPI_DEBUG */
/* Initialization/Query functions */
static int WIN_VideoInit(SDL_VideoDevice *_this);
static void WIN_VideoQuit(SDL_VideoDevice *_this);
/* Hints */
SDL_bool g_WindowsEnableMessageLoop = SDL_TRUE;
SDL_bool g_WindowsEnableMenuMnemonics = SDL_FALSE;
SDL_bool g_WindowFrameUsableWhileCursorHidden = SDL_TRUE;
static void SDLCALL UpdateWindowsEnableMessageLoop(void *userdata, const char *name, const char *oldValue, const char *newValue)
{
g_WindowsEnableMessageLoop = SDL_GetStringBoolean(newValue, SDL_TRUE);
}
static void SDLCALL UpdateWindowsEnableMenuMnemonics(void *userdata, const char *name, const char *oldValue, const char *newValue)
{
g_WindowsEnableMenuMnemonics = SDL_GetStringBoolean(newValue, SDL_FALSE);
}
static void SDLCALL UpdateWindowFrameUsableWhileCursorHidden(void *userdata, const char *name, const char *oldValue, const char *newValue)
{
g_WindowFrameUsableWhileCursorHidden = SDL_GetStringBoolean(newValue, SDL_TRUE);
}
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
static int WIN_SuspendScreenSaver(SDL_VideoDevice *_this)
{
if (_this->suspend_screensaver) {
SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
} else {
SetThreadExecutionState(ES_CONTINUOUS);
}
return 0;
}
#endif
#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
extern void D3D12_XBOX_GetResolution(Uint32 *width, Uint32 *height);
#endif
/* Windows driver bootstrap functions */
static void WIN_DeleteDevice(SDL_VideoDevice *device)
{
SDL_VideoData *data = device->driverdata;
SDL_UnregisterApp();
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
if (data->userDLL) {
SDL_UnloadObject(data->userDLL);
}
if (data->shcoreDLL) {
SDL_UnloadObject(data->shcoreDLL);
}
#endif
if (device->wakeup_lock) {
SDL_DestroyMutex(device->wakeup_lock);
}
SDL_free(device->driverdata);
SDL_free(device);
}
static SDL_VideoDevice *WIN_CreateDevice(void)
{
SDL_VideoDevice *device;
SDL_VideoData *data;
SDL_RegisterApp(NULL, 0, NULL);
/* Initialize all variables that we clean on shutdown */
device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
if (device) {
data = (SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData));
} else {
data = NULL;
}
if (!data) {
SDL_free(device);
SDL_OutOfMemory();
return NULL;
}
device->driverdata = data;
device->wakeup_lock = SDL_CreateMutex();
device->system_theme = WIN_GetSystemTheme();
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
data->userDLL = SDL_LoadObject("USER32.DLL");
if (data->userDLL) {
/* *INDENT-OFF* */ /* clang-format off */
data->CloseTouchInputHandle = (BOOL (WINAPI *)(HTOUCHINPUT))SDL_LoadFunction(data->userDLL, "CloseTouchInputHandle");
data->GetTouchInputInfo = (BOOL (WINAPI *)(HTOUCHINPUT, UINT, PTOUCHINPUT, int)) SDL_LoadFunction(data->userDLL, "GetTouchInputInfo");
data->RegisterTouchWindow = (BOOL (WINAPI *)(HWND, ULONG))SDL_LoadFunction(data->userDLL, "RegisterTouchWindow");
data->SetProcessDPIAware = (BOOL (WINAPI *)(void))SDL_LoadFunction(data->userDLL, "SetProcessDPIAware");
data->SetProcessDpiAwarenessContext = (BOOL (WINAPI *)(DPI_AWARENESS_CONTEXT))SDL_LoadFunction(data->userDLL, "SetProcessDpiAwarenessContext");
data->SetThreadDpiAwarenessContext = (DPI_AWARENESS_CONTEXT (WINAPI *)(DPI_AWARENESS_CONTEXT))SDL_LoadFunction(data->userDLL, "SetThreadDpiAwarenessContext");
data->GetThreadDpiAwarenessContext = (DPI_AWARENESS_CONTEXT (WINAPI *)(void))SDL_LoadFunction(data->userDLL, "GetThreadDpiAwarenessContext");
data->GetAwarenessFromDpiAwarenessContext = (DPI_AWARENESS (WINAPI *)(DPI_AWARENESS_CONTEXT))SDL_LoadFunction(data->userDLL, "GetAwarenessFromDpiAwarenessContext");
data->EnableNonClientDpiScaling = (BOOL (WINAPI *)(HWND))SDL_LoadFunction(data->userDLL, "EnableNonClientDpiScaling");
data->AdjustWindowRectExForDpi = (BOOL (WINAPI *)(LPRECT, DWORD, BOOL, DWORD, UINT))SDL_LoadFunction(data->userDLL, "AdjustWindowRectExForDpi");
data->GetDpiForWindow = (UINT (WINAPI *)(HWND))SDL_LoadFunction(data->userDLL, "GetDpiForWindow");
data->AreDpiAwarenessContextsEqual = (BOOL (WINAPI *)(DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT))SDL_LoadFunction(data->userDLL, "AreDpiAwarenessContextsEqual");
data->IsValidDpiAwarenessContext = (BOOL (WINAPI *)(DPI_AWARENESS_CONTEXT))SDL_LoadFunction(data->userDLL, "IsValidDpiAwarenessContext");
/* *INDENT-ON* */ /* clang-format on */
} else {
SDL_ClearError();
}
data->shcoreDLL = SDL_LoadObject("SHCORE.DLL");
if (data->shcoreDLL) {
/* *INDENT-OFF* */ /* clang-format off */
data->GetDpiForMonitor = (HRESULT (WINAPI *)(HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *))SDL_LoadFunction(data->shcoreDLL, "GetDpiForMonitor");
data->SetProcessDpiAwareness = (HRESULT (WINAPI *)(PROCESS_DPI_AWARENESS))SDL_LoadFunction(data->shcoreDLL, "SetProcessDpiAwareness");
/* *INDENT-ON* */ /* clang-format on */
} else {
SDL_ClearError();
}
#endif /* #if !defined(__XBOXONE__) && !defined(__XBOXSERIES__) */
/* Set the function pointers */
device->VideoInit = WIN_VideoInit;
device->VideoQuit = WIN_VideoQuit;
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
device->RefreshDisplays = WIN_RefreshDisplays;
device->GetDisplayBounds = WIN_GetDisplayBounds;
device->GetDisplayUsableBounds = WIN_GetDisplayUsableBounds;
device->GetDisplayModes = WIN_GetDisplayModes;
device->SetDisplayMode = WIN_SetDisplayMode;
#endif
device->PumpEvents = WIN_PumpEvents;
device->WaitEventTimeout = WIN_WaitEventTimeout;
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
device->SendWakeupEvent = WIN_SendWakeupEvent;
device->SuspendScreenSaver = WIN_SuspendScreenSaver;
#endif
device->CreateSDLWindow = WIN_CreateWindow;
device->CreateSDLWindowFrom = WIN_CreateWindowFrom;
device->SetWindowTitle = WIN_SetWindowTitle;
device->SetWindowIcon = WIN_SetWindowIcon;
device->SetWindowPosition = WIN_SetWindowPosition;
device->SetWindowSize = WIN_SetWindowSize;
device->GetWindowBordersSize = WIN_GetWindowBordersSize;
device->GetWindowSizeInPixels = WIN_GetWindowSizeInPixels;
device->SetWindowOpacity = WIN_SetWindowOpacity;
device->ShowWindow = WIN_ShowWindow;
device->HideWindow = WIN_HideWindow;
device->RaiseWindow = WIN_RaiseWindow;
device->MaximizeWindow = WIN_MaximizeWindow;
device->MinimizeWindow = WIN_MinimizeWindow;
device->RestoreWindow = WIN_RestoreWindow;
device->SetWindowBordered = WIN_SetWindowBordered;
device->SetWindowResizable = WIN_SetWindowResizable;
device->SetWindowAlwaysOnTop = WIN_SetWindowAlwaysOnTop;
device->SetWindowFullscreen = WIN_SetWindowFullscreen;
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
device->GetWindowICCProfile = WIN_GetWindowICCProfile;
device->SetWindowMouseRect = WIN_SetWindowMouseRect;
device->SetWindowMouseGrab = WIN_SetWindowMouseGrab;
device->SetWindowKeyboardGrab = WIN_SetWindowKeyboardGrab;
#endif
device->DestroyWindow = WIN_DestroyWindow;
device->GetWindowWMInfo = WIN_GetWindowWMInfo;
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
device->CreateWindowFramebuffer = WIN_CreateWindowFramebuffer;
device->UpdateWindowFramebuffer = WIN_UpdateWindowFramebuffer;
device->DestroyWindowFramebuffer = WIN_DestroyWindowFramebuffer;
device->OnWindowEnter = WIN_OnWindowEnter;
device->SetWindowHitTest = WIN_SetWindowHitTest;
device->AcceptDragAndDrop = WIN_AcceptDragAndDrop;
device->FlashWindow = WIN_FlashWindow;
device->shape_driver.CreateShaper = Win32_CreateShaper;
device->shape_driver.SetWindowShape = Win32_SetWindowShape;
#endif
#ifdef SDL_VIDEO_OPENGL_WGL
device->GL_LoadLibrary = WIN_GL_LoadLibrary;
device->GL_GetProcAddress = WIN_GL_GetProcAddress;
device->GL_UnloadLibrary = WIN_GL_UnloadLibrary;
device->GL_CreateContext = WIN_GL_CreateContext;
device->GL_MakeCurrent = WIN_GL_MakeCurrent;
device->GL_SetSwapInterval = WIN_GL_SetSwapInterval;
device->GL_GetSwapInterval = WIN_GL_GetSwapInterval;
device->GL_SwapWindow = WIN_GL_SwapWindow;
device->GL_DeleteContext = WIN_GL_DeleteContext;
device->GL_GetEGLSurface = NULL;
#endif
#ifdef SDL_VIDEO_OPENGL_EGL
#ifdef SDL_VIDEO_OPENGL_WGL
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, SDL_FALSE)) {
#endif
/* Use EGL based functions */
device->GL_LoadLibrary = WIN_GLES_LoadLibrary;
device->GL_GetProcAddress = WIN_GLES_GetProcAddress;
device->GL_UnloadLibrary = WIN_GLES_UnloadLibrary;
device->GL_CreateContext = WIN_GLES_CreateContext;
device->GL_MakeCurrent = WIN_GLES_MakeCurrent;
device->GL_SetSwapInterval = WIN_GLES_SetSwapInterval;
device->GL_GetSwapInterval = WIN_GLES_GetSwapInterval;
device->GL_SwapWindow = WIN_GLES_SwapWindow;
device->GL_DeleteContext = WIN_GLES_DeleteContext;
device->GL_GetEGLSurface = WIN_GLES_GetEGLSurface;
#ifdef SDL_VIDEO_OPENGL_WGL
}
#endif
#endif
#ifdef SDL_VIDEO_VULKAN
device->Vulkan_LoadLibrary = WIN_Vulkan_LoadLibrary;
device->Vulkan_UnloadLibrary = WIN_Vulkan_UnloadLibrary;
device->Vulkan_GetInstanceExtensions = WIN_Vulkan_GetInstanceExtensions;
device->Vulkan_CreateSurface = WIN_Vulkan_CreateSurface;
#endif
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
device->StartTextInput = WIN_StartTextInput;
device->StopTextInput = WIN_StopTextInput;
device->SetTextInputRect = WIN_SetTextInputRect;
device->ClearComposition = WIN_ClearComposition;
device->IsTextInputShown = WIN_IsTextInputShown;
device->SetClipboardData = WIN_SetClipboardData;
device->GetClipboardData = WIN_GetClipboardData;
device->HasClipboardData = WIN_HasClipboardData;
#endif
#ifdef SDL_GDK_TEXTINPUT
GDK_EnsureHints();
device->StartTextInput = GDK_StartTextInput;
device->StopTextInput = GDK_StopTextInput;
device->SetTextInputRect = GDK_SetTextInputRect;
device->ClearComposition = GDK_ClearComposition;
device->IsTextInputShown = GDK_IsTextInputShown;
device->HasScreenKeyboardSupport = GDK_HasScreenKeyboardSupport;
device->ShowScreenKeyboard = GDK_ShowScreenKeyboard;
device->HideScreenKeyboard = GDK_HideScreenKeyboard;
device->IsScreenKeyboardShown = GDK_IsScreenKeyboardShown;
#endif
device->free = WIN_DeleteDevice;
device->quirk_flags = VIDEO_DEVICE_QUIRK_HAS_POPUP_WINDOW_SUPPORT;
return device;
}
VideoBootStrap WINDOWS_bootstrap = {
"windows", "SDL Windows video driver", WIN_CreateDevice
};
static BOOL WIN_DeclareDPIAwareUnaware(SDL_VideoDevice *_this)
{
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
SDL_VideoData *data = _this->driverdata;
if (data->SetProcessDpiAwarenessContext) {
return data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);
} else if (data->SetProcessDpiAwareness) {
/* Windows 8.1 */
return SUCCEEDED(data->SetProcessDpiAwareness(PROCESS_DPI_UNAWARE));
}
#endif
return FALSE;
}
static BOOL WIN_DeclareDPIAwareSystem(SDL_VideoDevice *_this)
{
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
SDL_VideoData *data = _this->driverdata;
if (data->SetProcessDpiAwarenessContext) {
/* Windows 10, version 1607 */
return data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE);
} else if (data->SetProcessDpiAwareness) {
/* Windows 8.1 */
return SUCCEEDED(data->SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE));
} else if (data->SetProcessDPIAware) {
/* Windows Vista */
return data->SetProcessDPIAware();
}
#endif
return FALSE;
}
static BOOL WIN_DeclareDPIAwarePerMonitor(SDL_VideoDevice *_this)
{
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
SDL_VideoData *data = _this->driverdata;
if (data->SetProcessDpiAwarenessContext) {
/* Windows 10, version 1607 */
return data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
} else if (data->SetProcessDpiAwareness) {
/* Windows 8.1 */
return SUCCEEDED(data->SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE));
} else {
/* Older OS: fall back to system DPI aware */
return WIN_DeclareDPIAwareSystem(_this);
}
#else
return FALSE;
#endif
}
static BOOL WIN_DeclareDPIAwarePerMonitorV2(SDL_VideoDevice *_this)
{
#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
return FALSE;
#else
SDL_VideoData *data = _this->driverdata;
/* Declare DPI aware (may have been done in external code or a manifest, as well) */
if (data->SetProcessDpiAwarenessContext) {
/* Windows 10, version 1607 */
/* NOTE: SetThreadDpiAwarenessContext doesn't work here with OpenGL - the OpenGL contents
end up still getting OS scaled. (tested on Windows 10 21H1 19043.1348, NVIDIA 496.49)
NOTE: Enabling DPI awareness through Windows Explorer
(right click .exe -> Properties -> Compatibility -> High DPI Settings ->
check "Override high DPI Scaling behaviour", select Application) gives
a DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE context (at least on Windows 10 21H1), and
setting DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 will fail.
NOTE: Entering exclusive fullscreen in a DPI_AWARENESS_CONTEXT_UNAWARE process
appears to cause Windows to change the .exe manifest to DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
on future launches. This means attempting to use DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
will fail in the future until you manually clear the "Override high DPI Scaling behaviour"
setting in Windows Explorer (tested on Windows 10 21H2).
*/
if (data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) {
return TRUE;
} else {
return WIN_DeclareDPIAwarePerMonitor(_this);
}
} else {
/* Older OS: fall back to per-monitor (or system) */
return WIN_DeclareDPIAwarePerMonitor(_this);
}
#endif
}
#ifdef HIGHDPI_DEBUG
static const char *WIN_GetDPIAwareness(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->driverdata;
if (data->GetThreadDpiAwarenessContext && data->AreDpiAwarenessContextsEqual) {
DPI_AWARENESS_CONTEXT context = data->GetThreadDpiAwarenessContext();
if (data->AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE)) {
return "unaware";
} else if (data->AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_SYSTEM_AWARE)) {
return "system";
} else if (data->AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE)) {
return "permonitor";
} else if (data->AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) {
return "permonitorv2";
} else if (data->AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED)) {
return "unaware_gdiscaled";
}
}
return "";
}
#endif
static void WIN_InitDPIAwareness(SDL_VideoDevice *_this)
{
const char *hint = SDL_GetHint("SDL_WINDOWS_DPI_AWARENESS");
if (hint == NULL || SDL_strcmp(hint, "permonitorv2") == 0) {
WIN_DeclareDPIAwarePerMonitorV2(_this);
} else if (SDL_strcmp(hint, "permonitor") == 0) {
WIN_DeclareDPIAwarePerMonitor(_this);
} else if (SDL_strcmp(hint, "system") == 0) {
WIN_DeclareDPIAwareSystem(_this);
} else if (SDL_strcmp(hint, "unaware") == 0) {
WIN_DeclareDPIAwareUnaware(_this);
}
}
int WIN_VideoInit(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->driverdata;
WIN_InitDPIAwareness(_this);
#ifdef HIGHDPI_DEBUG
SDL_Log("DPI awareness: %s", WIN_GetDPIAwareness(_this));
#endif
#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
/* For Xbox, we just need to create the single display */
{
SDL_DisplayMode mode;
SDL_zero(mode);
D3D12_XBOX_GetResolution(&mode.w, &mode.h);
mode.refresh_rate = 60.0f;
mode.format = SDL_PIXELFORMAT_ARGB8888;
SDL_AddBasicVideoDisplay(&mode);
}
#else /*!defined(__XBOXONE__) && !defined(__XBOXSERIES__)*/
if (WIN_InitModes(_this) < 0) {
return -1;
}
WIN_InitKeyboard(_this);
WIN_InitMouse(_this);
#endif
SDL_AddHintCallback(SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP, UpdateWindowsEnableMessageLoop, NULL);
SDL_AddHintCallback(SDL_HINT_WINDOWS_ENABLE_MENU_MNEMONICS, UpdateWindowsEnableMenuMnemonics, NULL);
SDL_AddHintCallback(SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN, UpdateWindowFrameUsableWhileCursorHidden, NULL);
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
data->_SDL_WAKEUP = RegisterWindowMessageA("_SDL_WAKEUP");
#endif
return 0;
}
void WIN_VideoQuit(SDL_VideoDevice *_this)
{
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
WIN_QuitModes(_this);
WIN_QuitKeyboard(_this);
WIN_QuitMouse(_this);
#endif
}
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
#define D3D_DEBUG_INFO
#include <d3d9.h>
#ifdef D3D_DEBUG_INFO
#ifndef D3D_SDK_VERSION
#define D3D_SDK_VERSION (32 | 0x80000000)
#endif
#ifndef D3D9b_SDK_VERSION
#define D3D9b_SDK_VERSION (31 | 0x80000000)
#endif
#else /**/
#ifndef D3D_SDK_VERSION
#define D3D_SDK_VERSION 32
#endif
#ifndef D3D9b_SDK_VERSION
#define D3D9b_SDK_VERSION 31
#endif
#endif
SDL_bool D3D_LoadDLL(void **pD3DDLL, IDirect3D9 **pDirect3D9Interface)
{
*pD3DDLL = SDL_LoadObject("D3D9.DLL");
if (*pD3DDLL) {
/* *INDENT-OFF* */ /* clang-format off */
typedef IDirect3D9 *(WINAPI *Direct3DCreate9_t)(UINT SDKVersion);
typedef HRESULT (WINAPI* Direct3DCreate9Ex_t)(UINT SDKVersion, IDirect3D9Ex** ppD3D);
/* *INDENT-ON* */ /* clang-format on */
Direct3DCreate9_t Direct3DCreate9Func;
if (SDL_GetHintBoolean(SDL_HINT_WINDOWS_USE_D3D9EX, SDL_FALSE)) {
Direct3DCreate9Ex_t Direct3DCreate9ExFunc;
Direct3DCreate9ExFunc = (Direct3DCreate9Ex_t)SDL_LoadFunction(*pD3DDLL, "Direct3DCreate9Ex");
if (Direct3DCreate9ExFunc) {
IDirect3D9Ex *pDirect3D9ExInterface;
HRESULT hr = Direct3DCreate9ExFunc(D3D_SDK_VERSION, &pDirect3D9ExInterface);
if (SUCCEEDED(hr)) {
const GUID IDirect3D9_GUID = { 0x81bdcbca, 0x64d4, 0x426d, { 0xae, 0x8d, 0xad, 0x1, 0x47, 0xf4, 0x27, 0x5c } };
hr = IDirect3D9Ex_QueryInterface(pDirect3D9ExInterface, &IDirect3D9_GUID, (void **)pDirect3D9Interface);
IDirect3D9Ex_Release(pDirect3D9ExInterface);
if (SUCCEEDED(hr)) {
return SDL_TRUE;
}
}
}
}
Direct3DCreate9Func = (Direct3DCreate9_t)SDL_LoadFunction(*pD3DDLL, "Direct3DCreate9");
if (Direct3DCreate9Func) {
*pDirect3D9Interface = Direct3DCreate9Func(D3D_SDK_VERSION);
if (*pDirect3D9Interface) {
return SDL_TRUE;
}
}
SDL_UnloadObject(*pD3DDLL);
*pD3DDLL = NULL;
}
*pDirect3D9Interface = NULL;
return SDL_FALSE;
}
int SDL_Direct3D9GetAdapterIndex(SDL_DisplayID displayID)
{
void *pD3DDLL;
IDirect3D9 *pD3D;
if (!D3D_LoadDLL(&pD3DDLL, &pD3D)) {
SDL_SetError("Unable to create Direct3D interface");
return D3DADAPTER_DEFAULT;
} else {
SDL_DisplayData *pData = SDL_GetDisplayDriverData(displayID);
int adapterIndex = D3DADAPTER_DEFAULT;
if (pData == NULL) {
SDL_SetError("Invalid display index");
adapterIndex = -1; /* make sure we return something invalid */
} else {
char *displayName = WIN_StringToUTF8W(pData->DeviceName);
unsigned int count = IDirect3D9_GetAdapterCount(pD3D);
unsigned int i;
for (i = 0; i < count; i++) {
D3DADAPTER_IDENTIFIER9 id;
IDirect3D9_GetAdapterIdentifier(pD3D, i, 0, &id);
if (SDL_strcmp(id.DeviceName, displayName) == 0) {
adapterIndex = i;
break;
}
}
SDL_free(displayName);
}
/* free up the D3D stuff we inited */
IDirect3D9_Release(pD3D);
SDL_UnloadObject(pD3DDLL);
return adapterIndex;
}
}
#endif /* !defined(__XBOXONE__) && !defined(__XBOXSERIES__) */
#ifdef HAVE_DXGI_H
#define CINTERFACE
#define COBJMACROS
#include <dxgi.h>
static SDL_bool DXGI_LoadDLL(void **pDXGIDLL, IDXGIFactory **pDXGIFactory)
{
*pDXGIDLL = SDL_LoadObject("DXGI.DLL");
if (*pDXGIDLL) {
/* *INDENT-OFF* */ /* clang-format off */
typedef HRESULT (WINAPI *CreateDXGI_t)(REFIID riid, void **ppFactory);
/* *INDENT-ON* */ /* clang-format on */
CreateDXGI_t CreateDXGI;
CreateDXGI = (CreateDXGI_t)SDL_LoadFunction(*pDXGIDLL, "CreateDXGIFactory");
if (CreateDXGI) {
GUID dxgiGUID = { 0x7b7166ec, 0x21c7, 0x44ae, { 0xb2, 0x1a, 0xc9, 0xae, 0x32, 0x1a, 0xe3, 0x69 } };
if (!SUCCEEDED(CreateDXGI(&dxgiGUID, (void **)pDXGIFactory))) {
*pDXGIFactory = NULL;
}
}
if (!*pDXGIFactory) {
SDL_UnloadObject(*pDXGIDLL);
*pDXGIDLL = NULL;
return SDL_FALSE;
}
return SDL_TRUE;
} else {
*pDXGIFactory = NULL;
return SDL_FALSE;
}
}
#endif
SDL_bool SDL_DXGIGetOutputInfo(SDL_DisplayID displayID, int *adapterIndex, int *outputIndex)
{
#ifndef HAVE_DXGI_H
if (adapterIndex) {
*adapterIndex = -1;
}
if (outputIndex) {
*outputIndex = -1;
}
SDL_SetError("SDL was compiled without DXGI support due to missing dxgi.h header");
return SDL_FALSE;
#else
SDL_DisplayData *pData = SDL_GetDisplayDriverData(displayID);
void *pDXGIDLL;
char *displayName;
int nAdapter, nOutput;
IDXGIFactory *pDXGIFactory = NULL;
IDXGIAdapter *pDXGIAdapter;
IDXGIOutput *pDXGIOutput;
if (adapterIndex == NULL) {
SDL_InvalidParamError("adapterIndex");
return SDL_FALSE;
}
if (outputIndex == NULL) {
SDL_InvalidParamError("outputIndex");
return SDL_FALSE;
}
*adapterIndex = -1;
*outputIndex = -1;
if (pData == NULL) {
SDL_SetError("Invalid display index");
return SDL_FALSE;
}
if (!DXGI_LoadDLL(&pDXGIDLL, &pDXGIFactory)) {
SDL_SetError("Unable to create DXGI interface");
return SDL_FALSE;
}
displayName = WIN_StringToUTF8W(pData->DeviceName);
nAdapter = 0;
while (*adapterIndex == -1 && SUCCEEDED(IDXGIFactory_EnumAdapters(pDXGIFactory, nAdapter, &pDXGIAdapter))) {
nOutput = 0;
while (*adapterIndex == -1 && SUCCEEDED(IDXGIAdapter_EnumOutputs(pDXGIAdapter, nOutput, &pDXGIOutput))) {
DXGI_OUTPUT_DESC outputDesc;
if (SUCCEEDED(IDXGIOutput_GetDesc(pDXGIOutput, &outputDesc))) {
char *outputName = WIN_StringToUTF8W(outputDesc.DeviceName);
if (SDL_strcmp(outputName, displayName) == 0) {
*adapterIndex = nAdapter;
*outputIndex = nOutput;
}
SDL_free(outputName);
}
IDXGIOutput_Release(pDXGIOutput);
nOutput++;
}
IDXGIAdapter_Release(pDXGIAdapter);
nAdapter++;
}
SDL_free(displayName);
/* free up the DXGI factory */
IDXGIFactory_Release(pDXGIFactory);
SDL_UnloadObject(pDXGIDLL);
if (*adapterIndex == -1) {
return SDL_FALSE;
} else {
return SDL_TRUE;
}
#endif
}
SDL_SystemTheme WIN_GetSystemTheme(void)
{
SDL_SystemTheme theme = SDL_SYSTEM_THEME_LIGHT;
HKEY hKey;
DWORD dwType = REG_DWORD;
DWORD value = ~0U;
DWORD length = sizeof(value);
/* Technically this isn't the system theme, but it's the preference for applications */
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
if (RegQueryValueExW(hKey, L"AppsUseLightTheme", 0, &dwType, (LPBYTE)&value, &length) == ERROR_SUCCESS) {
if (value == 0) {
theme = SDL_SYSTEM_THEME_DARK;
}
}
RegCloseKey(hKey);
}
return theme;
}
SDL_bool WIN_IsPerMonitorV2DPIAware(SDL_VideoDevice *_this)
{
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
SDL_VideoData *data = _this->driverdata;
if (data->AreDpiAwarenessContextsEqual && data->GetThreadDpiAwarenessContext) {
/* Windows 10, version 1607 */
return (SDL_bool)data->AreDpiAwarenessContextsEqual(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2,
data->GetThreadDpiAwarenessContext());
}
#endif
return SDL_FALSE;
}
#endif /* SDL_VIDEO_DRIVER_WINDOWS */

View File

@ -0,0 +1,471 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_windowsvideo_h_
#define SDL_windowsvideo_h_
#include "../../core/windows/SDL_windows.h"
#include "../SDL_sysvideo.h"
#if defined(_MSC_VER) && (_MSC_VER >= 1500) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
#include <msctf.h>
#else
#include "SDL_msctf.h"
#endif
#include <imm.h>
#define MAX_CANDLIST 10
#define MAX_CANDLENGTH 256
#define MAX_CANDSIZE (sizeof(WCHAR) * MAX_CANDLIST * MAX_CANDLENGTH)
#include "SDL_windowsclipboard.h"
#include "SDL_windowsevents.h"
#include "SDL_windowsopengl.h"
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
#include "SDL_windowskeyboard.h"
#include "SDL_windowsmodes.h"
#include "SDL_windowsmouse.h"
#include "SDL_windowsopengles.h"
#endif
#include "SDL_windowswindow.h"
#if WINVER < 0x0601
/* Touch input definitions */
#define TWF_FINETOUCH 1
#define TWF_WANTPALM 2
#define TOUCHEVENTF_MOVE 0x0001
#define TOUCHEVENTF_DOWN 0x0002
#define TOUCHEVENTF_UP 0x0004
DECLARE_HANDLE(HTOUCHINPUT);
typedef struct _TOUCHINPUT
{
LONG x;
LONG y;
HANDLE hSource;
DWORD dwID;
DWORD dwFlags;
DWORD dwMask;
DWORD dwTime;
ULONG_PTR dwExtraInfo;
DWORD cxContact;
DWORD cyContact;
} TOUCHINPUT, *PTOUCHINPUT;
/* More-robust display information in Vista... */
/* This is a huge amount of data to be stuffing into three API calls. :( */
typedef struct DISPLAYCONFIG_PATH_SOURCE_INFO
{
LUID adapterId;
UINT32 id;
union
{
UINT32 modeInfoIdx;
struct
{
UINT32 cloneGroupId : 16;
UINT32 sourceModeInfoIdx : 16;
} DUMMYSTRUCTNAME;
} DUMMYUNIONNAME;
UINT32 statusFlags;
} DISPLAYCONFIG_PATH_SOURCE_INFO;
typedef struct DISPLAYCONFIG_RATIONAL
{
UINT32 Numerator;
UINT32 Denominator;
} DISPLAYCONFIG_RATIONAL;
typedef struct DISPLAYCONFIG_PATH_TARGET_INFO
{
LUID adapterId;
UINT32 id;
union
{
UINT32 modeInfoIdx;
struct
{
UINT32 desktopModeInfoIdx : 16;
UINT32 targetModeInfoIdx : 16;
} DUMMYSTRUCTNAME;
} DUMMYUNIONNAME;
UINT32 /*DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY*/ outputTechnology;
UINT32 /*DISPLAYCONFIG_ROTATION*/ rotation;
UINT32 /*DISPLAYCONFIG_SCALING*/ scaling;
DISPLAYCONFIG_RATIONAL refreshRate;
UINT32 /*DISPLAYCONFIG_SCANLINE_ORDERING*/ scanLineOrdering;
BOOL targetAvailable;
UINT32 statusFlags;
} DISPLAYCONFIG_PATH_TARGET_INFO;
typedef struct DISPLAYCONFIG_PATH_INFO
{
DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo;
DISPLAYCONFIG_PATH_TARGET_INFO targetInfo;
UINT32 flags;
} DISPLAYCONFIG_PATH_INFO;
typedef enum
{
DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1,
DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2,
DISPLAYCONFIG_MODE_INFO_TYPE_DESKTOP_IMAGE = 3,
DISPLAYCONFIG_MODE_INFO_TYPE_FORCE_UINT32 = 0xFFFFFFFF
} DISPLAYCONFIG_MODE_INFO_TYPE;
typedef struct DISPLAYCONFIG_2DREGION
{
UINT32 cx;
UINT32 cy;
} DISPLAYCONFIG_2DREGION;
typedef struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO
{
UINT64 pixelRate;
DISPLAYCONFIG_RATIONAL hSyncFreq;
DISPLAYCONFIG_RATIONAL vSyncFreq;
DISPLAYCONFIG_2DREGION activeSize;
DISPLAYCONFIG_2DREGION totalSize;
union
{
struct
{
UINT32 videoStandard : 16;
// Vertical refresh frequency divider
UINT32 vSyncFreqDivider : 6;
UINT32 reserved : 10;
} AdditionalSignalInfo;
UINT32 videoStandard;
} DUMMYUNIONNAME;
// Scan line ordering (e.g. progressive, interlaced).
UINT32 /*DISPLAYCONFIG_SCANLINE_ORDERING*/ scanLineOrdering;
} DISPLAYCONFIG_VIDEO_SIGNAL_INFO;
typedef struct DISPLAYCONFIG_SOURCE_MODE
{
UINT32 width;
UINT32 height;
UINT32 /*DISPLAYCONFIG_PIXELFORMAT*/ pixelFormat;
POINTL position;
} DISPLAYCONFIG_SOURCE_MODE;
typedef struct DISPLAYCONFIG_TARGET_MODE
{
DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo;
} DISPLAYCONFIG_TARGET_MODE;
typedef struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO
{
POINTL PathSourceSize;
RECTL DesktopImageRegion;
RECTL DesktopImageClip;
} DISPLAYCONFIG_DESKTOP_IMAGE_INFO;
typedef struct DISPLAYCONFIG_MODE_INFO
{
DISPLAYCONFIG_MODE_INFO_TYPE infoType;
UINT32 id;
LUID adapterId;
union
{
DISPLAYCONFIG_TARGET_MODE targetMode;
DISPLAYCONFIG_SOURCE_MODE sourceMode;
DISPLAYCONFIG_DESKTOP_IMAGE_INFO desktopImageInfo;
} DUMMYUNIONNAME;
} DISPLAYCONFIG_MODE_INFO;
typedef enum DISPLAYCONFIG_TOPOLOGY_ID
{
DISPLAYCONFIG_TOPOLOGY_INTERNAL = 0x00000001,
DISPLAYCONFIG_TOPOLOGY_CLONE = 0x00000002,
DISPLAYCONFIG_TOPOLOGY_EXTEND = 0x00000004,
DISPLAYCONFIG_TOPOLOGY_EXTERNAL = 0x00000008,
DISPLAYCONFIG_TOPOLOGY_FORCE_UINT32 = 0xFFFFFFFF
} DISPLAYCONFIG_TOPOLOGY_ID;
typedef enum
{
DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3,
DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4,
DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6,
DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = 7,
DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = 8,
DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO = 9,
DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE = 10,
DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL = 11,
DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32 = 0xFFFFFFFF
} DISPLAYCONFIG_DEVICE_INFO_TYPE;
typedef struct DISPLAYCONFIG_DEVICE_INFO_HEADER
{
DISPLAYCONFIG_DEVICE_INFO_TYPE type;
UINT32 size;
LUID adapterId;
UINT32 id;
} DISPLAYCONFIG_DEVICE_INFO_HEADER;
typedef struct DISPLAYCONFIG_SOURCE_DEVICE_NAME
{
DISPLAYCONFIG_DEVICE_INFO_HEADER header;
WCHAR viewGdiDeviceName[CCHDEVICENAME];
} DISPLAYCONFIG_SOURCE_DEVICE_NAME;
typedef struct DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS
{
union
{
struct
{
UINT32 friendlyNameFromEdid : 1;
UINT32 friendlyNameForced : 1;
UINT32 edidIdsValid : 1;
UINT32 reserved : 29;
} DUMMYSTRUCTNAME;
UINT32 value;
} DUMMYUNIONNAME;
} DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS;
typedef struct DISPLAYCONFIG_TARGET_DEVICE_NAME
{
DISPLAYCONFIG_DEVICE_INFO_HEADER header;
DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS flags;
UINT32 /*DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY*/ outputTechnology;
UINT16 edidManufactureId;
UINT16 edidProductCodeId;
UINT32 connectorInstance;
WCHAR monitorFriendlyDeviceName[64];
WCHAR monitorDevicePath[128];
} DISPLAYCONFIG_TARGET_DEVICE_NAME;
#define QDC_ONLY_ACTIVE_PATHS 0x00000002
#endif /* WINVER < 0x0601 */
#ifndef HAVE_SHELLSCALINGAPI_H
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;
typedef enum PROCESS_DPI_AWARENESS
{
PROCESS_DPI_UNAWARE = 0,
PROCESS_SYSTEM_DPI_AWARE = 1,
PROCESS_PER_MONITOR_DPI_AWARE = 2
} PROCESS_DPI_AWARENESS;
#else
#include <shellscalingapi.h>
#endif
#ifndef _DPI_AWARENESS_CONTEXTS_
typedef enum DPI_AWARENESS
{
DPI_AWARENESS_INVALID = -1,
DPI_AWARENESS_UNAWARE = 0,
DPI_AWARENESS_SYSTEM_AWARE = 1,
DPI_AWARENESS_PER_MONITOR_AWARE = 2
} DPI_AWARENESS;
DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
#define DPI_AWARENESS_CONTEXT_UNAWARE ((DPI_AWARENESS_CONTEXT)-1)
#define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ((DPI_AWARENESS_CONTEXT)-2)
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ((DPI_AWARENESS_CONTEXT)-3)
#endif /* _DPI_AWARENESS_CONTEXTS_ */
/* Windows 10 Creators Update */
#if NTDDI_VERSION < 0x0A000003
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4)
#endif /* NTDDI_VERSION < 0x0A000003 */
/* Windows 10 version 1809 */
#if NTDDI_VERSION < 0x0A000006
#define DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED ((DPI_AWARENESS_CONTEXT)-5)
#endif /* NTDDI_VERSION < 0x0A000006 */
typedef BOOL (*PFNSHFullScreen)(HWND, DWORD);
typedef void (*PFCoordTransform)(SDL_Window *, POINT *);
typedef struct
{
void **lpVtbl;
int refcount;
void *data;
} TSFSink;
#ifndef SDL_DISABLE_WINDOWS_IME
/* Definition from Win98DDK version of IMM.H */
typedef struct tagINPUTCONTEXT2
{
HWND hWnd;
BOOL fOpen;
POINT ptStatusWndPos;
POINT ptSoftKbdPos;
DWORD fdwConversion;
DWORD fdwSentence;
union
{
LOGFONTA A;
LOGFONTW W;
} lfFont;
COMPOSITIONFORM cfCompForm;
CANDIDATEFORM cfCandForm[4];
HIMCC hCompStr;
HIMCC hCandInfo;
HIMCC hGuideLine;
HIMCC hPrivate;
DWORD dwNumMsgBuf;
HIMCC hMsgBuf;
DWORD fdwInit;
DWORD dwReserve[3];
} INPUTCONTEXT2, *PINPUTCONTEXT2, NEAR *NPINPUTCONTEXT2, FAR *LPINPUTCONTEXT2;
#endif /* !SDL_DISABLE_WINDOWS_IME */
/* Private display data */
struct SDL_VideoData
{
int render;
DWORD clipboard_count;
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__) /* Xbox doesn't support user32/shcore*/
/* Touch input functions */
void *userDLL;
/* *INDENT-OFF* */ /* clang-format off */
BOOL (WINAPI *CloseTouchInputHandle)( HTOUCHINPUT );
BOOL (WINAPI *GetTouchInputInfo)( HTOUCHINPUT, UINT, PTOUCHINPUT, int );
BOOL (WINAPI *RegisterTouchWindow)( HWND, ULONG );
BOOL (WINAPI *SetProcessDPIAware)( void );
BOOL (WINAPI *SetProcessDpiAwarenessContext)( DPI_AWARENESS_CONTEXT );
DPI_AWARENESS_CONTEXT (WINAPI *SetThreadDpiAwarenessContext)( DPI_AWARENESS_CONTEXT );
DPI_AWARENESS_CONTEXT (WINAPI *GetThreadDpiAwarenessContext)( void );
DPI_AWARENESS (WINAPI *GetAwarenessFromDpiAwarenessContext)( DPI_AWARENESS_CONTEXT );
BOOL (WINAPI *EnableNonClientDpiScaling)( HWND );
BOOL (WINAPI *AdjustWindowRectExForDpi)( LPRECT, DWORD, BOOL, DWORD, UINT );
UINT (WINAPI *GetDpiForWindow)( HWND );
BOOL (WINAPI *AreDpiAwarenessContextsEqual)(DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT);
BOOL (WINAPI *IsValidDpiAwarenessContext)(DPI_AWARENESS_CONTEXT);
/* *INDENT-ON* */ /* clang-format on */
void *shcoreDLL;
/* *INDENT-OFF* */ /* clang-format off */
HRESULT (WINAPI *GetDpiForMonitor)( HMONITOR hmonitor,
MONITOR_DPI_TYPE dpiType,
UINT *dpiX,
UINT *dpiY );
HRESULT (WINAPI *SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS dpiAwareness);
/* *INDENT-ON* */ /* clang-format on */
#endif /*!defined(__XBOXONE__) && !defined(__XBOXSERIES__)*/
SDL_bool cleared;
#ifndef SDL_DISABLE_WINDOWS_IME
SDL_bool ime_com_initialized;
struct ITfThreadMgr *ime_threadmgr;
SDL_bool ime_initialized;
SDL_bool ime_enabled;
SDL_bool ime_available;
HWND ime_hwnd_main;
HWND ime_hwnd_current;
SDL_bool ime_suppress_endcomposition_event;
HIMC ime_himc;
WCHAR *ime_composition;
int ime_composition_length;
WCHAR ime_readingstring[16];
int ime_cursor;
SDL_bool ime_candlist;
WCHAR *ime_candidates;
DWORD ime_candcount;
DWORD ime_candref;
DWORD ime_candsel;
UINT ime_candpgsize;
int ime_candlistindexbase;
SDL_bool ime_candvertical;
SDL_bool ime_dirty;
SDL_Rect ime_rect;
SDL_Rect ime_candlistrect;
int ime_winwidth;
int ime_winheight;
HKL ime_hkl;
void *ime_himm32;
/* *INDENT-OFF* */ /* clang-format off */
UINT (WINAPI *GetReadingString)(HIMC himc, UINT uReadingBufLen, LPWSTR lpwReadingBuf, PINT pnErrorIndex, BOOL *pfIsVertical, PUINT puMaxReadingLen);
BOOL (WINAPI *ShowReadingWindow)(HIMC himc, BOOL bShow);
LPINPUTCONTEXT2 (WINAPI *ImmLockIMC)(HIMC himc);
BOOL (WINAPI *ImmUnlockIMC)(HIMC himc);
LPVOID (WINAPI *ImmLockIMCC)(HIMCC himcc);
BOOL (WINAPI *ImmUnlockIMCC)(HIMCC himcc);
/* *INDENT-ON* */ /* clang-format on */
SDL_bool ime_uiless;
struct ITfThreadMgrEx *ime_threadmgrex;
DWORD ime_uielemsinkcookie;
DWORD ime_alpnsinkcookie;
DWORD ime_openmodesinkcookie;
DWORD ime_convmodesinkcookie;
TSFSink *ime_uielemsink;
TSFSink *ime_ippasink;
LONG ime_uicontext;
#endif /* !SDL_DISABLE_WINDOWS_IME */
BYTE pre_hook_key_state[256];
UINT _SDL_WAKEUP;
};
extern SDL_bool g_WindowsEnableMessageLoop;
extern SDL_bool g_WindowsEnableMenuMnemonics;
extern SDL_bool g_WindowFrameUsableWhileCursorHidden;
typedef struct IDirect3D9 IDirect3D9;
extern SDL_bool D3D_LoadDLL(void **pD3DDLL, IDirect3D9 **pDirect3D9Interface);
extern SDL_SystemTheme WIN_GetSystemTheme(void);
extern SDL_bool WIN_IsPerMonitorV2DPIAware(SDL_VideoDevice *_this);
#endif /* SDL_windowsvideo_h_ */

View File

@ -0,0 +1,169 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
* @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's
* SDL_x11vulkan.c.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_WINDOWS)
#include "SDL_windowsvideo.h"
#include "SDL_windowswindow.h"
#include "SDL_windowsvulkan.h"
#include <SDL3/SDL_syswm.h>
int WIN_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
VkExtensionProperties *extensions = NULL;
Uint32 extensionCount = 0;
Uint32 i;
SDL_bool hasSurfaceExtension = SDL_FALSE;
SDL_bool hasWin32SurfaceExtension = SDL_FALSE;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
if (_this->vulkan_config.loader_handle) {
return SDL_SetError("Vulkan already loaded");
}
/* Load the Vulkan loader library */
if (path == NULL) {
path = SDL_getenv("SDL_VULKAN_LIBRARY");
}
if (path == NULL) {
path = "vulkan-1.dll";
}
_this->vulkan_config.loader_handle = SDL_LoadObject(path);
if (!_this->vulkan_config.loader_handle) {
return -1;
}
SDL_strlcpy(_this->vulkan_config.loader_path, path,
SDL_arraysize(_this->vulkan_config.loader_path));
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction(
_this->vulkan_config.loader_handle, "vkGetInstanceProcAddr");
if (!vkGetInstanceProcAddr) {
goto fail;
}
_this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr;
_this->vulkan_config.vkEnumerateInstanceExtensionProperties =
(void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)(
VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties");
if (!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) {
goto fail;
}
extensions = SDL_Vulkan_CreateInstanceExtensionsList(
(PFN_vkEnumerateInstanceExtensionProperties)
_this->vulkan_config.vkEnumerateInstanceExtensionProperties,
&extensionCount);
if (extensions == NULL) {
goto fail;
}
for (i = 0; i < extensionCount; i++) {
if (SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
hasSurfaceExtension = SDL_TRUE;
} else if (SDL_strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
hasWin32SurfaceExtension = SDL_TRUE;
}
}
SDL_free(extensions);
if (!hasSurfaceExtension) {
SDL_SetError("Installed Vulkan doesn't implement the " VK_KHR_SURFACE_EXTENSION_NAME " extension");
goto fail;
} else if (!hasWin32SurfaceExtension) {
SDL_SetError("Installed Vulkan doesn't implement the " VK_KHR_WIN32_SURFACE_EXTENSION_NAME "extension");
goto fail;
}
return 0;
fail:
SDL_UnloadObject(_this->vulkan_config.loader_handle);
_this->vulkan_config.loader_handle = NULL;
return -1;
}
void WIN_Vulkan_UnloadLibrary(SDL_VideoDevice *_this)
{
if (_this->vulkan_config.loader_handle) {
SDL_UnloadObject(_this->vulkan_config.loader_handle);
_this->vulkan_config.loader_handle = NULL;
}
}
SDL_bool WIN_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
unsigned *count,
const char **names)
{
static const char *const extensionsForWin32[] = {
VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME
};
if (!_this->vulkan_config.loader_handle) {
SDL_SetError("Vulkan is not loaded");
return SDL_FALSE;
}
return SDL_Vulkan_GetInstanceExtensions_Helper(
count, names, SDL_arraysize(extensionsForWin32),
extensionsForWin32);
}
SDL_bool WIN_Vulkan_CreateSurface(SDL_VideoDevice *_this,
SDL_Window *window,
VkInstance instance,
VkSurfaceKHR *surface)
{
SDL_WindowData *windowData = window->driverdata;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
(PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr;
PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR =
(PFN_vkCreateWin32SurfaceKHR)vkGetInstanceProcAddr(
instance,
"vkCreateWin32SurfaceKHR");
VkWin32SurfaceCreateInfoKHR createInfo;
VkResult result;
if (!_this->vulkan_config.loader_handle) {
SDL_SetError("Vulkan is not loaded");
return SDL_FALSE;
}
if (!vkCreateWin32SurfaceKHR) {
SDL_SetError(VK_KHR_WIN32_SURFACE_EXTENSION_NAME
" extension is not enabled in the Vulkan instance.");
return SDL_FALSE;
}
createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
createInfo.pNext = NULL;
createInfo.flags = 0;
createInfo.hinstance = windowData->hinstance;
createInfo.hwnd = windowData->hwnd;
result = vkCreateWin32SurfaceKHR(instance, &createInfo,
NULL, surface);
if (result != VK_SUCCESS) {
SDL_SetError("vkCreateWin32SurfaceKHR failed: %s",
SDL_Vulkan_GetResultString(result));
return SDL_FALSE;
}
return SDL_TRUE;
}
#endif

View File

@ -0,0 +1,49 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
* @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's
* SDL_x11vulkan.h.
*/
#include "SDL_internal.h"
#ifndef SDL_windowsvulkan_h_
#define SDL_windowsvulkan_h_
#include "../SDL_vulkan_internal.h"
#include "../SDL_sysvideo.h"
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_WINDOWS)
int WIN_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path);
void WIN_Vulkan_UnloadLibrary(SDL_VideoDevice *_this);
SDL_bool WIN_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
unsigned *count,
const char **names);
SDL_bool WIN_Vulkan_CreateSurface(SDL_VideoDevice *_this,
SDL_Window *window,
VkInstance instance,
VkSurfaceKHR *surface);
#endif
#endif /* SDL_windowsvulkan_h_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,117 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_windowswindow_h_
#define SDL_windowswindow_h_
#ifdef SDL_VIDEO_OPENGL_EGL
#include "../SDL_egl_c.h"
#else
#include "../SDL_sysvideo.h"
#endif
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
struct SDL_WindowData
{
SDL_Window *window;
HWND hwnd;
HWND parent;
HDC hdc;
HDC mdc;
HINSTANCE hinstance;
HBITMAP hbm;
WNDPROC wndproc;
HHOOK keyboard_hook;
SDL_bool created;
WPARAM mouse_button_flags;
LPARAM last_pointer_update;
WCHAR high_surrogate;
SDL_bool initializing;
SDL_bool expected_resize;
SDL_bool in_border_change;
SDL_bool in_title_click;
Uint8 focus_click_pending;
SDL_bool skip_update_clipcursor;
Uint64 last_updated_clipcursor;
SDL_bool mouse_relative_mode_center;
SDL_bool windowed_mode_was_maximized;
SDL_bool in_window_deactivation;
RECT cursor_clipped_rect;
SDL_Point last_raw_mouse_position;
SDL_bool mouse_tracked;
SDL_bool destroy_parent_with_window;
SDL_DisplayID last_displayID;
WCHAR *ICMFileName;
SDL_Window *keyboard_focus;
struct SDL_VideoData *videodata;
#ifdef SDL_VIDEO_OPENGL_EGL
EGLSurface egl_surface;
#endif
/* Whether we retain the content of the window when changing state */
UINT copybits_flag;
};
extern int WIN_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int WIN_CreateWindowFrom(SDL_VideoDevice *_this, SDL_Window *window, const void *data);
extern void WIN_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
extern int WIN_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon);
extern int WIN_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window);
extern void WIN_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window);
extern int WIN_GetWindowBordersSize(SDL_VideoDevice *_this, SDL_Window *window, int *top, int *left, int *bottom, int *right);
extern void WIN_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *width, int *height);
extern int WIN_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opacity);
extern void WIN_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void WIN_HideWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void WIN_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void WIN_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void WIN_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void WIN_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void WIN_SetWindowBordered(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool bordered);
extern void WIN_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool resizable);
extern void WIN_SetWindowAlwaysOnTop(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool on_top);
extern void WIN_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen);
extern void WIN_UpdateWindowICCProfile(SDL_Window *window, SDL_bool send_event);
extern void *WIN_GetWindowICCProfile(SDL_VideoDevice *_this, SDL_Window *window, size_t *size);
extern void WIN_SetWindowMouseRect(SDL_VideoDevice *_this, SDL_Window *window);
extern void WIN_SetWindowMouseGrab(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool grabbed);
extern void WIN_SetWindowKeyboardGrab(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool grabbed);
extern void WIN_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int WIN_GetWindowWMInfo(SDL_VideoDevice *_this, SDL_Window *window, struct SDL_SysWMinfo *info);
extern void WIN_OnWindowEnter(SDL_VideoDevice *_this, SDL_Window *window);
extern void WIN_UpdateClipCursor(SDL_Window *window);
extern int WIN_SetWindowHitTest(SDL_Window *window, SDL_bool enabled);
extern void WIN_AcceptDragAndDrop(SDL_Window *window, SDL_bool accept);
extern int WIN_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
extern void WIN_UpdateDarkModeForHWND(HWND hwnd);
extern int WIN_SetWindowPositionInternal(SDL_Window *window, UINT flags);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
#endif /* SDL_windowswindow_h_ */

1050
external/sdl/SDL/src/video/windows/wmmsg.h vendored Normal file

File diff suppressed because it is too large Load Diff