mirror of
https://github.com/love2d/megasource.git
synced 2026-08-21 05:02:11 +02:00
Add SDL3 3.1.1-preview
This commit is contained in:
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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_ */
|
||||
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_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"
|
||||
#define BFT_BITMAP 0x4d42 /* 'BM' */
|
||||
|
||||
/* 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 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) && ((BITMAPFILEHEADER *)bmp)->bfType == BFT_BITMAP) {
|
||||
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 = BFT_BITMAP;
|
||||
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_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) {
|
||||
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 */
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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_PollRawInput(SDL_VideoDevice *_this);
|
||||
extern void WIN_CheckKeyboardAndMouseHotplug(SDL_VideoDevice *_this, SDL_bool initial_check);
|
||||
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_ */
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
||||
#include "SDL_windowsvideo.h"
|
||||
|
||||
int WIN_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, SDL_PixelFormatEnum *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 -1;
|
||||
}
|
||||
|
||||
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) {
|
||||
/* 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 */
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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, SDL_PixelFormatEnum *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
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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 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
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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 */
|
||||
@@ -0,0 +1,851 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
||||
#include "SDL_windowsvideo.h"
|
||||
#include "../../events/SDL_displayevents_c.h"
|
||||
|
||||
#define COBJMACROS
|
||||
#include <dxgi1_6.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.biCompression == BI_RGB) {
|
||||
if (bmi->bmiHeader.biBitCount == 24) {
|
||||
mode->format = SDL_PIXELFORMAT_RGB24;
|
||||
} 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 = USER_DEFAULT_SCREEN_DPI;
|
||||
}
|
||||
return dpi / (float)USER_DEFAULT_SCREEN_DPI;
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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 || !pQueryDisplayConfig || !pDisplayConfigGetDeviceInfo) {
|
||||
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) || (!modes)) {
|
||||
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 SDL_bool WIN_GetMonitorDESC1(HMONITOR hMonitor, DXGI_OUTPUT_DESC1 *desc)
|
||||
{
|
||||
typedef HRESULT (WINAPI * PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory);
|
||||
PFN_CREATE_DXGI_FACTORY CreateDXGIFactoryFunc = NULL;
|
||||
void *hDXGIMod = NULL;
|
||||
SDL_bool found = SDL_FALSE;
|
||||
|
||||
#ifdef SDL_PLATFORM_WINRT
|
||||
CreateDXGIFactoryFunc = CreateDXGIFactory1;
|
||||
#else
|
||||
hDXGIMod = SDL_LoadObject("dxgi.dll");
|
||||
if (hDXGIMod) {
|
||||
CreateDXGIFactoryFunc = (PFN_CREATE_DXGI_FACTORY)SDL_LoadFunction(hDXGIMod, "CreateDXGIFactory1");
|
||||
}
|
||||
#endif
|
||||
if (CreateDXGIFactoryFunc) {
|
||||
static const GUID SDL_IID_IDXGIFactory1 = { 0x770aae78, 0xf26f, 0x4dba, { 0xa8, 0x29, 0x25, 0x3c, 0x83, 0xd1, 0xb3, 0x87 } };
|
||||
static const GUID SDL_IID_IDXGIOutput6 = { 0x068346e8, 0xaaec, 0x4b84, { 0xad, 0xd7, 0x13, 0x7f, 0x51, 0x3f, 0x77, 0xa1 } };
|
||||
IDXGIFactory1 *dxgiFactory;
|
||||
|
||||
if (SUCCEEDED(CreateDXGIFactoryFunc(&SDL_IID_IDXGIFactory1, (void **)&dxgiFactory))) {
|
||||
IDXGIAdapter1 *dxgiAdapter;
|
||||
UINT adapter = 0;
|
||||
while (!found && SUCCEEDED(IDXGIFactory1_EnumAdapters1(dxgiFactory, adapter, &dxgiAdapter))) {
|
||||
IDXGIOutput *dxgiOutput;
|
||||
UINT output = 0;
|
||||
while (!found && SUCCEEDED(IDXGIAdapter1_EnumOutputs(dxgiAdapter, output, &dxgiOutput))) {
|
||||
IDXGIOutput6 *dxgiOutput6;
|
||||
if (SUCCEEDED(IDXGIOutput_QueryInterface(dxgiOutput, &SDL_IID_IDXGIOutput6, (void **)&dxgiOutput6))) {
|
||||
if (SUCCEEDED(IDXGIOutput6_GetDesc1(dxgiOutput6, desc))) {
|
||||
if (desc->Monitor == hMonitor) {
|
||||
found = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
IDXGIOutput6_Release(dxgiOutput6);
|
||||
}
|
||||
IDXGIOutput_Release(dxgiOutput);
|
||||
++output;
|
||||
}
|
||||
IDXGIAdapter1_Release(dxgiAdapter);
|
||||
++adapter;
|
||||
}
|
||||
IDXGIFactory2_Release(dxgiFactory);
|
||||
}
|
||||
}
|
||||
if (hDXGIMod) {
|
||||
SDL_UnloadObject(hDXGIMod);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
static SDL_bool WIN_GetMonitorPathInfo(HMONITOR hMonitor, DISPLAYCONFIG_PATH_INFO *path_info)
|
||||
{
|
||||
LONG result;
|
||||
MONITORINFOEXW view_info;
|
||||
UINT32 i;
|
||||
UINT32 num_path_array_elements = 0;
|
||||
UINT32 num_mode_info_array_elements = 0;
|
||||
DISPLAYCONFIG_PATH_INFO *path_infos = NULL, *new_path_infos;
|
||||
DISPLAYCONFIG_MODE_INFO *mode_infos = NULL, *new_mode_infos;
|
||||
SDL_bool found = SDL_FALSE;
|
||||
|
||||
SDL_zero(view_info);
|
||||
view_info.cbSize = sizeof(view_info);
|
||||
if (!GetMonitorInfoW(hMonitor, (MONITORINFO *)&view_info)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
do {
|
||||
if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &num_path_array_elements, &num_mode_info_array_elements) != ERROR_SUCCESS) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
new_path_infos = (DISPLAYCONFIG_PATH_INFO *)SDL_realloc(path_infos, num_path_array_elements * sizeof(*path_infos));
|
||||
if (!new_path_infos) {
|
||||
goto done;
|
||||
}
|
||||
path_infos = new_path_infos;
|
||||
|
||||
new_mode_infos = (DISPLAYCONFIG_MODE_INFO *)SDL_realloc(mode_infos, num_mode_info_array_elements * sizeof(*mode_infos));
|
||||
if (!new_mode_infos) {
|
||||
goto done;
|
||||
}
|
||||
mode_infos = new_mode_infos;
|
||||
|
||||
result = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &num_path_array_elements, path_infos, &num_mode_info_array_elements, mode_infos, NULL);
|
||||
|
||||
} while (result == ERROR_INSUFFICIENT_BUFFER);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
for (i = 0; i < num_path_array_elements; ++i) {
|
||||
DISPLAYCONFIG_SOURCE_DEVICE_NAME device_name;
|
||||
|
||||
SDL_zero(device_name);
|
||||
device_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
|
||||
device_name.header.size = sizeof(device_name);
|
||||
device_name.header.adapterId = path_infos[i].sourceInfo.adapterId;
|
||||
device_name.header.id = path_infos[i].sourceInfo.id;
|
||||
if (DisplayConfigGetDeviceInfo(&device_name.header) == ERROR_SUCCESS) {
|
||||
if (SDL_wcscmp(view_info.szDevice, device_name.viewGdiDeviceName) == 0) {
|
||||
SDL_copyp(path_info, &path_infos[i]);
|
||||
found = SDL_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
SDL_free(path_infos);
|
||||
SDL_free(mode_infos);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static float WIN_GetSDRWhitePoint(HMONITOR hMonitor)
|
||||
{
|
||||
DISPLAYCONFIG_PATH_INFO path_info;
|
||||
float SDR_white_point = 1.0f;
|
||||
|
||||
if (WIN_GetMonitorPathInfo(hMonitor, &path_info)) {
|
||||
DISPLAYCONFIG_SDR_WHITE_LEVEL white_level;
|
||||
|
||||
SDL_zero(white_level);
|
||||
white_level.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL;
|
||||
white_level.header.size = sizeof(white_level);
|
||||
white_level.header.adapterId = path_info.targetInfo.adapterId;
|
||||
white_level.header.id = path_info.targetInfo.id;
|
||||
if (DisplayConfigGetDeviceInfo(&white_level.header) == ERROR_SUCCESS &&
|
||||
white_level.SDRWhiteLevel > 0) {
|
||||
SDR_white_point = (white_level.SDRWhiteLevel / 1000.0f);
|
||||
}
|
||||
}
|
||||
return SDR_white_point;
|
||||
}
|
||||
|
||||
static void WIN_GetHDRProperties(SDL_VideoDevice *_this, HMONITOR hMonitor, SDL_HDRDisplayProperties *HDR)
|
||||
{
|
||||
DXGI_OUTPUT_DESC1 desc;
|
||||
|
||||
SDL_zerop(HDR);
|
||||
|
||||
if (WIN_GetMonitorDESC1(hMonitor, &desc)) {
|
||||
if (desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) {
|
||||
HDR->SDR_white_point = WIN_GetSDRWhitePoint(hMonitor);
|
||||
HDR->HDR_headroom = (desc.MaxLuminance / 80.0f) / HDR->SDR_white_point;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, ¤t_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 (driverdata->state != DisplayRemoved) {
|
||||
/* We've already enumerated this display, don't move it */
|
||||
return;
|
||||
}
|
||||
|
||||
if (index >= _this->num_displays) {
|
||||
/* This should never happen due to the check above, but just in case... */
|
||||
return;
|
||||
}
|
||||
|
||||
if (moved) {
|
||||
SDL_VideoDisplay *tmp;
|
||||
|
||||
tmp = _this->displays[index];
|
||||
_this->displays[index] = _this->displays[i];
|
||||
_this->displays[i] = 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_HDRDisplayProperties HDR;
|
||||
|
||||
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);
|
||||
WIN_GetHDRProperties(_this, hMonitor, &HDR);
|
||||
SDL_SetDisplayHDRProperties(existing_display, &HDR);
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
displaydata = (SDL_DisplayData *)SDL_calloc(1, sizeof(*displaydata));
|
||||
if (!displaydata) {
|
||||
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) {
|
||||
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);
|
||||
WIN_GetHDRProperties(_this, hMonitor, &display.HDR);
|
||||
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 = (SDL_DisplayModeData *)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_ADDED, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WIN_QuitModes(SDL_VideoDevice *_this)
|
||||
{
|
||||
/* All fullscreen windows should have restored modes by now */
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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_ */
|
||||
@@ -0,0 +1,540 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
||||
#include "SDL_windowsvideo.h"
|
||||
#include "SDL_windowsevents.h"
|
||||
#include "SDL_windowsrawinput.h"
|
||||
|
||||
#include "../SDL_video_c.h"
|
||||
#include "../../events/SDL_mouse_c.h"
|
||||
#include "../../joystick/usb_ids.h"
|
||||
|
||||
DWORD SDL_last_warp_time = 0;
|
||||
HCURSOR SDL_cursor = NULL;
|
||||
static SDL_Cursor *SDL_blank_cursor = NULL;
|
||||
|
||||
static SDL_Cursor *WIN_CreateDefaultCursor()
|
||||
{
|
||||
SDL_Cursor *cursor = (SDL_Cursor *)SDL_calloc(1, sizeof(*cursor));
|
||||
if (cursor) {
|
||||
cursor->driverdata = LoadCursor(NULL, IDC_ARROW);
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
static SDL_bool IsMonochromeSurface(SDL_Surface *surface)
|
||||
{
|
||||
int x, y;
|
||||
Uint8 r, g, b, a;
|
||||
|
||||
SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
|
||||
|
||||
for (y = 0; y < surface->h; y++) {
|
||||
for (x = 0; x < surface->w; x++) {
|
||||
SDL_ReadSurfacePixel(surface, x, y, &r, &g, &b, &a);
|
||||
|
||||
/* Black or white pixel. */
|
||||
if (!((r == 0x00 && g == 0x00 && b == 0x00) || (r == 0xff && g == 0xff && b == 0xff))) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Transparent or opaque pixel. */
|
||||
if (!(a == 0x00 || a == 0xff)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static HBITMAP CreateColorBitmap(SDL_Surface *surface)
|
||||
{
|
||||
HBITMAP bitmap;
|
||||
BITMAPINFO bi;
|
||||
void *pixels;
|
||||
|
||||
SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
|
||||
|
||||
SDL_zero(bi);
|
||||
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bi.bmiHeader.biWidth = surface->w;
|
||||
bi.bmiHeader.biHeight = -surface->h; /* Invert height to make the top-down DIB. */
|
||||
bi.bmiHeader.biPlanes = 1;
|
||||
bi.bmiHeader.biBitCount = 32;
|
||||
bi.bmiHeader.biCompression = BI_RGB;
|
||||
|
||||
bitmap = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &pixels, NULL, 0);
|
||||
if (!bitmap || !pixels) {
|
||||
WIN_SetError("CreateDIBSection()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_memcpy(pixels, surface->pixels, surface->pitch * surface->h);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/* Generate bitmap with a mask and optional monochrome image data.
|
||||
*
|
||||
* For info on the expected mask format see:
|
||||
* https://devblogs.microsoft.com/oldnewthing/20101018-00/?p=12513
|
||||
*/
|
||||
static HBITMAP CreateMaskBitmap(SDL_Surface *surface, SDL_bool is_monochrome)
|
||||
{
|
||||
HBITMAP bitmap;
|
||||
SDL_bool isstack;
|
||||
void *pixels;
|
||||
int x, y;
|
||||
Uint8 r, g, b, a;
|
||||
Uint8 *dst;
|
||||
const int pitch = ((surface->w + 15) & ~15) / 8;
|
||||
const int size = pitch * surface->h;
|
||||
static const unsigned char masks[] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 };
|
||||
|
||||
SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
|
||||
|
||||
pixels = SDL_small_alloc(Uint8, size * (is_monochrome ? 2 : 1), &isstack);
|
||||
if (!pixels) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dst = (Uint8 *)pixels;
|
||||
|
||||
/* Make the mask completely transparent. */
|
||||
SDL_memset(dst, 0xff, size);
|
||||
if (is_monochrome) {
|
||||
SDL_memset(dst + size, 0x00, size);
|
||||
}
|
||||
|
||||
for (y = 0; y < surface->h; y++, dst += pitch) {
|
||||
for (x = 0; x < surface->w; x++) {
|
||||
SDL_ReadSurfacePixel(surface, x, y, &r, &g, &b, &a);
|
||||
|
||||
if (a != 0) {
|
||||
/* Reset bit of an opaque pixel. */
|
||||
dst[x >> 3] &= ~masks[x & 7];
|
||||
}
|
||||
|
||||
if (is_monochrome && !(r == 0x00 && g == 0x00 && b == 0x00)) {
|
||||
/* Set bit of white or inverted pixel. */
|
||||
dst[size + (x >> 3)] |= masks[x & 7];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bitmap = CreateBitmap(surface->w, surface->h * (is_monochrome ? 2 : 1), 1, 1, pixels);
|
||||
SDL_small_free(pixels, isstack);
|
||||
if (!bitmap) {
|
||||
WIN_SetError("CreateBitmap()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
static SDL_Cursor *WIN_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
|
||||
{
|
||||
HCURSOR hcursor;
|
||||
SDL_Cursor *cursor;
|
||||
ICONINFO ii;
|
||||
SDL_bool is_monochrome = IsMonochromeSurface(surface);
|
||||
|
||||
SDL_zero(ii);
|
||||
ii.fIcon = FALSE;
|
||||
ii.xHotspot = (DWORD)hot_x;
|
||||
ii.yHotspot = (DWORD)hot_y;
|
||||
ii.hbmMask = CreateMaskBitmap(surface, is_monochrome);
|
||||
ii.hbmColor = is_monochrome ? NULL : CreateColorBitmap(surface);
|
||||
|
||||
if (!ii.hbmMask || (!is_monochrome && !ii.hbmColor)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hcursor = CreateIconIndirect(&ii);
|
||||
|
||||
DeleteObject(ii.hbmMask);
|
||||
if (ii.hbmColor) {
|
||||
DeleteObject(ii.hbmColor);
|
||||
}
|
||||
|
||||
if (!hcursor) {
|
||||
WIN_SetError("CreateIconIndirect()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cursor = (SDL_Cursor *)SDL_calloc(1, sizeof(*cursor));
|
||||
if (cursor) {
|
||||
cursor->driverdata = hcursor;
|
||||
} else {
|
||||
DestroyCursor(hcursor);
|
||||
}
|
||||
|
||||
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;
|
||||
case SDL_SYSTEM_CURSOR_WINDOW_TOPLEFT:
|
||||
name = IDC_SIZENWSE;
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_WINDOW_TOP:
|
||||
name = IDC_SIZENS;
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_WINDOW_TOPRIGHT:
|
||||
name = IDC_SIZENESW;
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_WINDOW_RIGHT:
|
||||
name = IDC_SIZEWE;
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_WINDOW_BOTTOMRIGHT:
|
||||
name = IDC_SIZENWSE;
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_WINDOW_BOTTOM:
|
||||
name = IDC_SIZENS;
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_WINDOW_BOTTOMLEFT:
|
||||
name = IDC_SIZENESW;
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_WINDOW_LEFT:
|
||||
name = IDC_SIZEWE;
|
||||
break;
|
||||
}
|
||||
|
||||
cursor = (SDL_Cursor *)SDL_calloc(1, sizeof(*cursor));
|
||||
if (cursor) {
|
||||
HCURSOR hcursor;
|
||||
|
||||
hcursor = LoadCursor(NULL, name);
|
||||
|
||||
cursor->driverdata = hcursor;
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
static void WIN_FreeCursor(SDL_Cursor *cursor)
|
||||
{
|
||||
HCURSOR hcursor = (HCURSOR)cursor->driverdata;
|
||||
|
||||
DestroyCursor(hcursor);
|
||||
SDL_free(cursor);
|
||||
}
|
||||
|
||||
static int WIN_ShowCursor(SDL_Cursor *cursor)
|
||||
{
|
||||
if (!cursor) {
|
||||
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 */
|
||||
#ifdef _MSC_VER /* We explicitly want to use GetTickCount(), not GetTickCount64() */
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 28159)
|
||||
#endif
|
||||
SDL_last_warp_time = GetTickCount();
|
||||
if (!SDL_last_warp_time) {
|
||||
SDL_last_warp_time = 1;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
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_GLOBAL_MOUSE_ID, SDL_FALSE, 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 WIN_SetRawMouseEnabled(SDL_GetVideoDevice(), 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 (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 = USER_DEFAULT_SCREEN_DPI; // 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 */
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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_ */
|
||||
@@ -0,0 +1,905 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_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 -1;
|
||||
}
|
||||
|
||||
/* 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(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_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(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_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)
|
||||
{
|
||||
SDL_FunctionPointer func;
|
||||
|
||||
/* This is to pick up extensions */
|
||||
func = (SDL_FunctionPointer)_this->gl_data->wglGetProcAddress(proc);
|
||||
if (!func) {
|
||||
/* This is probably a normal GL function */
|
||||
func = (SDL_FunctionPointer)GetProcAddress((HMODULE)_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) {
|
||||
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) {
|
||||
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;
|
||||
|
||||
int qAttrib = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
|
||||
int srgb = 0;
|
||||
|
||||
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);
|
||||
|
||||
/* Check whether we actually got an SRGB capable buffer */
|
||||
_this->gl_data->wglGetPixelFormatAttribivARB(hdc, pixel_format, 0, 1, &qAttrib, &srgb);
|
||||
_this->gl_config.framebuffer_srgb_capable = srgb;
|
||||
}
|
||||
|
||||
_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) {
|
||||
window = SDL_GL_GetCurrentWindow();
|
||||
if (!window) {
|
||||
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;
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_OPENGL_WGL */
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_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(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_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);
|
||||
|
||||
#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_ */
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_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) {
|
||||
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) {
|
||||
/* !!! 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 */
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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_ */
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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)
|
||||
|
||||
#include "SDL_windowsvideo.h"
|
||||
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
||||
#include "SDL_windowsevents.h"
|
||||
|
||||
#include "../../joystick/usb_ids.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SDL_bool done;
|
||||
HANDLE ready_event;
|
||||
HANDLE done_event;
|
||||
HANDLE thread;
|
||||
} RawInputThreadData;
|
||||
|
||||
static RawInputThreadData thread_data = {
|
||||
SDL_FALSE,
|
||||
INVALID_HANDLE_VALUE,
|
||||
INVALID_HANDLE_VALUE,
|
||||
INVALID_HANDLE_VALUE
|
||||
};
|
||||
|
||||
static DWORD WINAPI WIN_RawInputThread(LPVOID param)
|
||||
{
|
||||
SDL_VideoDevice *_this = SDL_GetVideoDevice();
|
||||
RawInputThreadData *data = (RawInputThreadData *)param;
|
||||
RAWINPUTDEVICE devices[2];
|
||||
HWND window;
|
||||
|
||||
window = CreateWindowEx(0, TEXT("Message"), NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
|
||||
if (!window) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
devices[0].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
|
||||
devices[0].usUsage = USB_USAGE_GENERIC_MOUSE;
|
||||
devices[0].dwFlags = 0;
|
||||
devices[0].hwndTarget = window;
|
||||
|
||||
devices[1].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
|
||||
devices[1].usUsage = USB_USAGE_GENERIC_KEYBOARD;
|
||||
devices[1].dwFlags = 0;
|
||||
devices[1].hwndTarget = window;
|
||||
|
||||
if (!RegisterRawInputDevices(devices, SDL_arraysize(devices), sizeof(devices[0]))) {
|
||||
DestroyWindow(window);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure we get events as soon as possible */
|
||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
|
||||
|
||||
/* Tell the parent we're ready to go! */
|
||||
SetEvent(data->ready_event);
|
||||
|
||||
while (!data->done) {
|
||||
if (MsgWaitForMultipleObjects(1, &data->done_event, FALSE, INFINITE, QS_RAWINPUT) != (WAIT_OBJECT_0 + 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Clear the queue status so MsgWaitForMultipleObjects() will wait again */
|
||||
(void)GetQueueStatus(QS_RAWINPUT);
|
||||
|
||||
WIN_PollRawInput(_this);
|
||||
}
|
||||
|
||||
devices[0].dwFlags |= RIDEV_REMOVE;
|
||||
devices[1].dwFlags |= RIDEV_REMOVE;
|
||||
RegisterRawInputDevices(devices, SDL_arraysize(devices), sizeof(devices[0]));
|
||||
|
||||
DestroyWindow(window);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void CleanupRawInputThreadData(RawInputThreadData *data)
|
||||
{
|
||||
if (data->thread != INVALID_HANDLE_VALUE) {
|
||||
data->done = SDL_TRUE;
|
||||
SetEvent(data->done_event);
|
||||
WaitForSingleObject(data->thread, 3000);
|
||||
CloseHandle(data->thread);
|
||||
data->thread = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (data->ready_event != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(data->ready_event);
|
||||
data->ready_event = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (data->done_event != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(data->done_event);
|
||||
data->done_event = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
static int WIN_SetRawInputEnabled(SDL_VideoDevice *_this, SDL_bool enabled)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
if (enabled) {
|
||||
HANDLE handles[2];
|
||||
|
||||
thread_data.ready_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if (thread_data.ready_event == INVALID_HANDLE_VALUE) {
|
||||
WIN_SetError("CreateEvent");
|
||||
goto done;
|
||||
}
|
||||
|
||||
thread_data.done = SDL_FALSE;
|
||||
thread_data.done_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if (thread_data.done_event == INVALID_HANDLE_VALUE) {
|
||||
WIN_SetError("CreateEvent");
|
||||
goto done;
|
||||
}
|
||||
|
||||
thread_data.thread = CreateThread(NULL, 0, WIN_RawInputThread, &thread_data, 0, NULL);
|
||||
if (thread_data.thread == INVALID_HANDLE_VALUE) {
|
||||
WIN_SetError("CreateThread");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Wait for the thread to signal ready or exit */
|
||||
handles[0] = thread_data.ready_event;
|
||||
handles[1] = thread_data.thread;
|
||||
if (WaitForMultipleObjects(2, handles, FALSE, INFINITE) != WAIT_OBJECT_0) {
|
||||
SDL_SetError("Couldn't set up raw input handling");
|
||||
goto done;
|
||||
}
|
||||
result = 0;
|
||||
} else {
|
||||
CleanupRawInputThreadData(&thread_data);
|
||||
result = 0;
|
||||
}
|
||||
|
||||
done:
|
||||
if (enabled && result < 0) {
|
||||
CleanupRawInputThreadData(&thread_data);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int WIN_UpdateRawInputEnabled(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *data = _this->driverdata;
|
||||
SDL_bool enabled = (data->raw_mouse_enabled || data->raw_keyboard_enabled);
|
||||
if (enabled != data->raw_input_enabled) {
|
||||
if (WIN_SetRawInputEnabled(_this, enabled) == 0) {
|
||||
data->raw_input_enabled = enabled;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WIN_SetRawMouseEnabled(SDL_VideoDevice *_this, SDL_bool enabled)
|
||||
{
|
||||
SDL_VideoData *data = _this->driverdata;
|
||||
data->raw_mouse_enabled = enabled;
|
||||
return WIN_UpdateRawInputEnabled(_this);
|
||||
}
|
||||
|
||||
int WIN_SetRawKeyboardEnabled(SDL_VideoDevice *_this, SDL_bool enabled)
|
||||
{
|
||||
SDL_VideoData *data = _this->driverdata;
|
||||
data->raw_keyboard_enabled = enabled;
|
||||
return WIN_UpdateRawInputEnabled(_this);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int WIN_SetRawMouseEnabled(SDL_VideoDevice *_this, SDL_bool enabled)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
int WIN_SetRawKeyboardEnabled(SDL_VideoDevice *_this, SDL_bool enabled)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
#endif /* !SDL_PLATFORM_XBOXONE && !SDL_PLATFORM_XBOXSERIES */
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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_windowsrawinput_h_
|
||||
#define SDL_windowsrawinput_h_
|
||||
|
||||
extern int WIN_SetRawMouseEnabled(SDL_VideoDevice *_this, SDL_bool enabled);
|
||||
extern int WIN_SetRawKeyboardEnabled(SDL_VideoDevice *_this, SDL_bool enabled);
|
||||
|
||||
#endif /* SDL_windowsrawinput_h_ */
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
||||
#include "SDL_windowsvideo.h"
|
||||
#include "SDL_windowsshape.h"
|
||||
|
||||
|
||||
static void AddRegion(HRGN *mask, int x1, int y1, int x2, int y2)
|
||||
{
|
||||
HRGN region = CreateRectRgn(x1, y1, x2, y2);
|
||||
if (*mask) {
|
||||
CombineRgn(*mask, *mask, region, RGN_OR);
|
||||
DeleteObject(region);
|
||||
} else {
|
||||
*mask = region;
|
||||
}
|
||||
}
|
||||
|
||||
static HRGN GenerateSpanListRegion(SDL_Surface *shape, int offset_x, int offset_y)
|
||||
{
|
||||
HRGN mask = NULL;
|
||||
int x, y;
|
||||
int span_start = -1;
|
||||
|
||||
for (y = 0; y < shape->h; ++y) {
|
||||
const Uint8 *a = (const Uint8 *)shape->pixels + y * shape->pitch;
|
||||
for (x = 0; x < shape->w; ++x) {
|
||||
if (*a == SDL_ALPHA_TRANSPARENT) {
|
||||
if (span_start != -1) {
|
||||
AddRegion(&mask, offset_x + span_start, offset_y + y, offset_x + x, offset_y + y + 1);
|
||||
span_start = -1;
|
||||
}
|
||||
} else {
|
||||
if (span_start == -1) {
|
||||
span_start = x;
|
||||
}
|
||||
}
|
||||
a += 4;
|
||||
}
|
||||
if (span_start != -1) {
|
||||
/* Add the final span */
|
||||
AddRegion(&mask, offset_x + span_start, offset_y + y, offset_x + x, offset_y + y + 1);
|
||||
span_start = -1;
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
int WIN_UpdateWindowShape(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *shape)
|
||||
{
|
||||
SDL_WindowData *data = window->driverdata;
|
||||
HRGN mask = NULL;
|
||||
|
||||
/* Generate a set of spans for the region */
|
||||
if (shape) {
|
||||
SDL_Surface *stretched = NULL;
|
||||
RECT rect;
|
||||
|
||||
if (shape->w != window->w || shape->h != window->h) {
|
||||
stretched = SDL_CreateSurface(window->w, window->h, SDL_PIXELFORMAT_ARGB32);
|
||||
if (!stretched) {
|
||||
return -1;
|
||||
}
|
||||
if (SDL_SoftStretch(shape, NULL, stretched, NULL, SDL_SCALEMODE_LINEAR) < 0) {
|
||||
SDL_DestroySurface(stretched);
|
||||
return -1;
|
||||
}
|
||||
shape = stretched;
|
||||
}
|
||||
|
||||
rect.top = 0;
|
||||
rect.left = 0;
|
||||
rect.bottom = 0;
|
||||
rect.right = 0;
|
||||
if (!(SDL_GetWindowFlags(data->window) & SDL_WINDOW_BORDERLESS)) {
|
||||
WIN_AdjustWindowRectForHWND(data->hwnd, &rect, 0);
|
||||
}
|
||||
|
||||
mask = GenerateSpanListRegion(shape, -rect.left, -rect.top);
|
||||
|
||||
if (!(SDL_GetWindowFlags(data->window) & SDL_WINDOW_BORDERLESS)) {
|
||||
/* Add the window borders */
|
||||
/* top */
|
||||
AddRegion(&mask, 0, 0, -rect.left + shape->w + rect.right + 1, -rect.top + 1);
|
||||
/* left */
|
||||
AddRegion(&mask, 0, -rect.top, -rect.left + 1, -rect.top + shape->h + 1);
|
||||
/* right */
|
||||
AddRegion(&mask, -rect.left + shape->w, -rect.top, -rect.left + shape->w + rect.right + 1, -rect.top + shape->h + 1);
|
||||
/* bottom */
|
||||
AddRegion(&mask, 0, -rect.top + shape->h, -rect.left + shape->w + rect.right + 1, -rect.top + shape->h + rect.bottom + 1);
|
||||
}
|
||||
|
||||
if (stretched) {
|
||||
SDL_DestroySurface(stretched);
|
||||
}
|
||||
}
|
||||
if (!SetWindowRgn(data->hwnd, mask, TRUE)) {
|
||||
return WIN_SetError("SetWindowRgn failed");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* defined(SDL_VIDEO_DRIVER_WINDOWS) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) */
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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_
|
||||
|
||||
extern int WIN_UpdateWindowShape(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *shape);
|
||||
|
||||
#endif /* SDL_windowsshape_h_ */
|
||||
@@ -0,0 +1,747 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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
|
||||
|
||||
#ifdef SDL_VIDEO_VULKAN
|
||||
#include "../SDL_vulkan_internal.h"
|
||||
#endif
|
||||
#include "../SDL_sysvideo.h"
|
||||
#include "../SDL_pixels_c.h"
|
||||
#include "../../SDL_hints_c.h"
|
||||
#include "../../core/windows/SDL_hid.h"
|
||||
|
||||
#include "SDL_windowsvideo.h"
|
||||
#include "SDL_windowsframebuffer.h"
|
||||
#include "SDL_windowsmessagebox.h"
|
||||
#include "SDL_windowsrawinput.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 UpdateWindowsRawKeyboard(void *userdata, const char *name, const char *oldValue, const char *newValue)
|
||||
{
|
||||
SDL_VideoDevice *_this = (SDL_VideoDevice *)userdata;
|
||||
SDL_bool enabled = SDL_GetStringBoolean(newValue, SDL_TRUE);
|
||||
WIN_SetRawKeyboardEnabled(_this, enabled);
|
||||
}
|
||||
|
||||
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(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_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(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_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(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_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->rawinput);
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
device->driverdata = data;
|
||||
device->wakeup_lock = SDL_CreateMutex();
|
||||
device->system_theme = WIN_GetSystemTheme();
|
||||
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_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(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) */
|
||||
|
||||
/* Set the function pointers */
|
||||
device->VideoInit = WIN_VideoInit;
|
||||
device->VideoQuit = WIN_VideoQuit;
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_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(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
device->SendWakeupEvent = WIN_SendWakeupEvent;
|
||||
device->SuspendScreenSaver = WIN_SuspendScreenSaver;
|
||||
#endif
|
||||
|
||||
device->CreateSDLWindow = WIN_CreateWindow;
|
||||
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(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
device->GetWindowICCProfile = WIN_GetWindowICCProfile;
|
||||
device->SetWindowMouseRect = WIN_SetWindowMouseRect;
|
||||
device->SetWindowMouseGrab = WIN_SetWindowMouseGrab;
|
||||
device->SetWindowKeyboardGrab = WIN_SetWindowKeyboardGrab;
|
||||
#endif
|
||||
device->DestroyWindow = WIN_DestroyWindow;
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_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->ShowWindowSystemMenu = WIN_ShowWindowSystemMenu;
|
||||
device->SetWindowFocusable = WIN_SetWindowFocusable;
|
||||
device->UpdateWindowShape = WIN_UpdateWindowShape;
|
||||
#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(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
device->StartTextInput = WIN_StartTextInput;
|
||||
device->StopTextInput = WIN_StopTextInput;
|
||||
device->SetTextInputRect = WIN_SetTextInputRect;
|
||||
device->ClearComposition = WIN_ClearComposition;
|
||||
|
||||
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->HasScreenKeyboardSupport = GDK_HasScreenKeyboardSupport;
|
||||
device->ShowScreenKeyboard = GDK_ShowScreenKeyboard;
|
||||
device->HideScreenKeyboard = GDK_HideScreenKeyboard;
|
||||
device->IsScreenKeyboardShown = GDK_IsScreenKeyboardShown;
|
||||
#endif
|
||||
|
||||
device->free = WIN_DeleteDevice;
|
||||
|
||||
device->device_caps = VIDEO_DEVICE_CAPS_HAS_POPUP_WINDOW_SUPPORT |
|
||||
VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS;
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
VideoBootStrap WINDOWS_bootstrap = {
|
||||
"windows", "SDL Windows video driver", WIN_CreateDevice,
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
WIN_ShowMessageBox
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
};
|
||||
|
||||
static BOOL WIN_DeclareDPIAwareUnaware(SDL_VideoDevice *_this)
|
||||
{
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_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(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_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(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_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(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_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 || 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(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_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(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)*/
|
||||
if (WIN_InitModes(_this) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
WIN_InitKeyboard(_this);
|
||||
WIN_InitMouse(_this);
|
||||
WIN_InitDeviceNotification();
|
||||
WIN_CheckKeyboardAndMouseHotplug(_this, SDL_TRUE);
|
||||
#endif
|
||||
|
||||
SDL_AddHintCallback(SDL_HINT_WINDOWS_RAW_KEYBOARD, UpdateWindowsRawKeyboard, _this);
|
||||
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(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
data->_SDL_WAKEUP = RegisterWindowMessageA("_SDL_WAKEUP");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WIN_VideoQuit(SDL_VideoDevice *_this)
|
||||
{
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
WIN_QuitModes(_this);
|
||||
WIN_QuitDeviceNotification();
|
||||
WIN_QuitKeyboard(_this);
|
||||
WIN_QuitMouse(_this);
|
||||
#endif
|
||||
|
||||
SDL_DelHintCallback(SDL_HINT_WINDOWS_RAW_KEYBOARD, UpdateWindowsRawKeyboard, _this);
|
||||
SDL_DelHintCallback(SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP, UpdateWindowsEnableMessageLoop, NULL);
|
||||
SDL_DelHintCallback(SDL_HINT_WINDOWS_ENABLE_MENU_MNEMONICS, UpdateWindowsEnableMenuMnemonics, NULL);
|
||||
SDL_DelHintCallback(SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN, UpdateWindowFrameUsableWhileCursorHidden, NULL);
|
||||
|
||||
WIN_SetRawMouseEnabled(_this, SDL_FALSE);
|
||||
WIN_SetRawKeyboardEnabled(_this, SDL_FALSE);
|
||||
}
|
||||
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_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) {
|
||||
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(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_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) {
|
||||
SDL_InvalidParamError("adapterIndex");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (!outputIndex) {
|
||||
SDL_InvalidParamError("outputIndex");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
*adapterIndex = -1;
|
||||
*outputIndex = -1;
|
||||
|
||||
if (!pData) {
|
||||
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(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
SDL_VideoData *data = _this->driverdata;
|
||||
|
||||
if (data->AreDpiAwarenessContextsEqual && data->GetThreadDpiAwarenessContext) {
|
||||
/* Windows 10, version 1607 */
|
||||
return data->AreDpiAwarenessContextsEqual(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, data->GetThreadDpiAwarenessContext());
|
||||
}
|
||||
#endif
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
|
||||
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_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(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
#include "SDL_windowsshape.h"
|
||||
#include "SDL_windowskeyboard.h"
|
||||
#include "SDL_windowsmodes.h"
|
||||
#include "SDL_windowsmouse.h"
|
||||
#include "SDL_windowsopengles.h"
|
||||
#endif
|
||||
|
||||
#include "SDL_windowswindow.h"
|
||||
|
||||
#ifndef USER_DEFAULT_SCREEN_DPI
|
||||
#define USER_DEFAULT_SCREEN_DPI 96
|
||||
#endif
|
||||
|
||||
#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(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_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(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)*/
|
||||
|
||||
SDL_bool cleared;
|
||||
|
||||
BYTE *rawinput;
|
||||
UINT rawinput_offset;
|
||||
UINT rawinput_size;
|
||||
UINT rawinput_count;
|
||||
Uint64 last_rawinput_poll;
|
||||
SDL_Point last_raw_mouse_position;
|
||||
SDL_bool raw_mouse_enabled;
|
||||
SDL_bool raw_keyboard_enabled;
|
||||
SDL_bool pending_E1_key_sequence;
|
||||
SDL_bool raw_input_enabled;
|
||||
|
||||
#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_ */
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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_vulkan_internal.h"
|
||||
|
||||
#include "SDL_windowsvideo.h"
|
||||
#include "SDL_windowswindow.h"
|
||||
|
||||
#include "SDL_windowsvulkan.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) {
|
||||
path = SDL_getenv("SDL_VULKAN_LIBRARY");
|
||||
}
|
||||
if (!path) {
|
||||
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 = (SDL_FunctionPointer)vkGetInstanceProcAddr;
|
||||
_this->vulkan_config.vkEnumerateInstanceExtensionProperties =
|
||||
(SDL_FunctionPointer)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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
char const* const* WIN_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
|
||||
Uint32 *count)
|
||||
{
|
||||
static const char *const extensionsForWin32[] = {
|
||||
VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME
|
||||
};
|
||||
if(count) { *count = SDL_arraysize(extensionsForWin32); }
|
||||
return extensionsForWin32;
|
||||
}
|
||||
|
||||
SDL_bool WIN_Vulkan_CreateSurface(SDL_VideoDevice *_this,
|
||||
SDL_Window *window,
|
||||
VkInstance instance,
|
||||
const struct VkAllocationCallbacks *allocator,
|
||||
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, allocator, surface);
|
||||
if (result != VK_SUCCESS) {
|
||||
SDL_SetError("vkCreateWin32SurfaceKHR failed: %s",
|
||||
SDL_Vulkan_GetResultString(result));
|
||||
return SDL_FALSE;
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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_
|
||||
|
||||
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_WINDOWS)
|
||||
|
||||
#include "../SDL_vulkan_internal.h"
|
||||
#include "../SDL_sysvideo.h"
|
||||
|
||||
int WIN_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path);
|
||||
void WIN_Vulkan_UnloadLibrary(SDL_VideoDevice *_this);
|
||||
char const* const* WIN_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
|
||||
Uint32 *count);
|
||||
SDL_bool WIN_Vulkan_CreateSurface(SDL_VideoDevice *_this,
|
||||
SDL_Window *window,
|
||||
VkInstance instance,
|
||||
const struct VkAllocationCallbacks *allocator,
|
||||
VkSurfaceKHR *surface);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SDL_windowsvulkan_h_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2024 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
|
||||
|
||||
typedef enum SDL_WindowRect
|
||||
{
|
||||
SDL_WINDOWRECT_CURRENT,
|
||||
SDL_WINDOWRECT_WINDOWED,
|
||||
SDL_WINDOWRECT_FLOATING
|
||||
} SDL_WindowRect;
|
||||
|
||||
struct SDL_WindowData
|
||||
{
|
||||
SDL_Window *window;
|
||||
HWND hwnd;
|
||||
HWND parent;
|
||||
HDC hdc;
|
||||
HDC mdc;
|
||||
HINSTANCE hinstance;
|
||||
HBITMAP hbm;
|
||||
WNDPROC wndproc;
|
||||
HHOOK keyboard_hook;
|
||||
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;
|
||||
SDL_bool floating_rect_pending;
|
||||
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;
|
||||
UINT windowed_mode_corner_rounding;
|
||||
COLORREF dwma_border_color;
|
||||
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, SDL_PropertiesID create_props);
|
||||
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 int 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 int WIN_SetWindowMouseRect(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern int WIN_SetWindowMouseGrab(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool grabbed);
|
||||
extern int WIN_SetWindowKeyboardGrab(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool grabbed);
|
||||
extern void WIN_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
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, SDL_WindowRect rect_type);
|
||||
extern void WIN_ShowWindowSystemMenu(SDL_Window *window, int x, int y);
|
||||
extern int WIN_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool focusable);
|
||||
extern int WIN_AdjustWindowRect(SDL_Window *window, int *x, int *y, int *width, int *height, SDL_WindowRect rect_type);
|
||||
extern int WIN_AdjustWindowRectForHWND(HWND hwnd, LPRECT lpRect, UINT frame_dpi);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SDL_windowswindow_h_ */
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user