ObsidianDragon - DragonX ImGui Wallet

Full-node GUI wallet for DragonX cryptocurrency.
Built with Dear ImGui, SDL3, and OpenGL3/DX11.

Features:
- Send/receive shielded and transparent transactions
- Autoshield with merged transaction display
- Built-in CPU mining (xmrig)
- Peer management and network monitoring
- Wallet encryption with PIN lock
- QR code generation for receive addresses
- Transaction history with pagination
- Console for direct RPC commands
- Cross-platform (Linux, Windows)
This commit is contained in:
2026-02-26 02:31:52 -06:00
commit 3aee55b49c
306 changed files with 177789 additions and 0 deletions

View File

@@ -0,0 +1,351 @@
// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
#include "dx11_context.h"
#ifdef _WIN32
#include <SDL3/SDL.h>
#include <dcomp.h>
#include "../util/logger.h"
// Not defined in older MinGW SDK headers
#ifndef WS_EX_NOREDIRECTIONBITMAP
#define WS_EX_NOREDIRECTIONBITMAP 0x00200000L
#endif
namespace dragonx {
namespace platform {
// Helper to get HWND from SDL window
static HWND getHWND(SDL_Window* window) {
if (!window) return nullptr;
SDL_PropertiesID props = SDL_GetWindowProperties(window);
if (props == 0) return nullptr;
return (HWND)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr);
}
bool DX11Context::init(SDL_Window* window)
{
HWND hwnd = getHWND(window);
if (!hwnd) {
DEBUG_LOGF("DX11: Failed to get HWND from SDL window\n");
return false;
}
hwnd_ = hwnd;
// Ensure WS_EX_NOREDIRECTIONBITMAP is set. The main code creates the
// HWND with this style, but if someone passes a different window we try
// to set it here as a fallback. We also call SetWindowPos with
// SWP_FRAMECHANGED so the DWM re-evaluates the extended style.
LONG_PTR exStyle = GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
if (!(exStyle & WS_EX_NOREDIRECTIONBITMAP)) {
SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle | WS_EX_NOREDIRECTIONBITMAP);
SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
LONG_PTR verify = GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
if (verify & WS_EX_NOREDIRECTIONBITMAP)
DEBUG_LOGF("DX11: WS_EX_NOREDIRECTIONBITMAP set via fallback path\n");
else
DEBUG_LOGF("DX11: WARNING - WS_EX_NOREDIRECTIONBITMAP could NOT be set!\n");
} else {
DEBUG_LOGF("DX11: WS_EX_NOREDIRECTIONBITMAP already present (good)\n");
}
fflush(stdout);
// Create D3D11 device and context
D3D_FEATURE_LEVEL featureLevel;
const D3D_FEATURE_LEVEL featureLevelArray[] = {
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_0,
};
UINT createDeviceFlags = 0;
#ifdef DRAGONX_DEBUG
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
// Need BGRA support for DirectComposition
createDeviceFlags |= D3D11_CREATE_DEVICE_BGRA_SUPPORT;
HRESULT hr = D3D11CreateDevice(
nullptr, // Default adapter
D3D_DRIVER_TYPE_HARDWARE, // Hardware rendering
nullptr, // No software module
createDeviceFlags,
featureLevelArray,
2,
D3D11_SDK_VERSION,
&device_,
&featureLevel,
&deviceContext_
);
if (FAILED(hr)) {
DEBUG_LOGF("DX11: D3D11CreateDevice failed (HRESULT 0x%08lx)\n", hr);
return false;
}
DEBUG_LOGF("DX11: Device created (feature level %d.%d)\n",
(featureLevel >> 12) & 0xF, (featureLevel >> 8) & 0xF);
// Get DXGI device for factory access and DirectComposition
IDXGIDevice* dxgiDevice = nullptr;
hr = device_->QueryInterface(IID_PPV_ARGS(&dxgiDevice));
if (FAILED(hr)) {
DEBUG_LOGF("DX11: QueryInterface IDXGIDevice failed\n");
shutdown();
return false;
}
IDXGIAdapter* dxgiAdapter = nullptr;
hr = dxgiDevice->GetAdapter(&dxgiAdapter);
if (FAILED(hr)) {
dxgiDevice->Release();
DEBUG_LOGF("DX11: GetAdapter failed\n");
shutdown();
return false;
}
IDXGIFactory2* dxgiFactory = nullptr;
hr = dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory));
dxgiAdapter->Release();
if (FAILED(hr)) {
dxgiDevice->Release();
DEBUG_LOGF("DX11: GetParent IDXGIFactory2 failed\n");
shutdown();
return false;
}
// ---------------------------------------------------------------
// Strategy: CreateSwapChainForComposition + DirectComposition
//
// DXGI_ALPHA_MODE_PREMULTIPLIED only works with composition swap chains.
// CreateSwapChainForHwnd does NOT support premultiplied alpha.
// We must use DirectComposition to bind the composition swap chain
// to the window. This is how Windows Terminal achieves transparency.
// ---------------------------------------------------------------
DXGI_SWAP_CHAIN_DESC1 sd = {};
sd.Width = 0; // Auto-detect from HWND
sd.Height = 0;
sd.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
sd.Stereo = FALSE;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.BufferCount = 2;
sd.Scaling = DXGI_SCALING_STRETCH;
sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
sd.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
sd.Flags = 0;
// CreateSwapChainForComposition needs explicit width/height
RECT clientRect;
GetClientRect(hwnd, &clientRect);
sd.Width = clientRect.right - clientRect.left;
sd.Height = clientRect.bottom - clientRect.top;
if (sd.Width == 0) sd.Width = 1400;
if (sd.Height == 0) sd.Height = 900;
hr = dxgiFactory->CreateSwapChainForComposition(
device_,
&sd,
nullptr,
&swapChain_
);
if (SUCCEEDED(hr)) {
DEBUG_LOGF("DX11: Composition swap chain created (%ux%u, PREMULTIPLIED alpha)\n",
sd.Width, sd.Height);
// Create DirectComposition device and bind swap chain to HWND
hr = DCompositionCreateDevice(dxgiDevice, IID_PPV_ARGS(&dcompDevice_));
if (SUCCEEDED(hr)) {
hr = dcompDevice_->CreateTargetForHwnd(hwnd, TRUE, &dcompTarget_);
}
if (SUCCEEDED(hr)) {
hr = dcompDevice_->CreateVisual(&dcompVisual_);
}
if (SUCCEEDED(hr)) {
hr = dcompVisual_->SetContent(swapChain_);
}
if (SUCCEEDED(hr)) {
hr = dcompTarget_->SetRoot(dcompVisual_);
}
if (SUCCEEDED(hr)) {
hr = dcompDevice_->Commit();
}
if (SUCCEEDED(hr)) {
hasAlpha_ = true;
DEBUG_LOGF("DX11: DirectComposition bound to HWND (alpha compositing active)\n");
fflush(stdout);
} else {
DEBUG_LOGF("DX11: DirectComposition setup failed (0x%08lx), falling back\n", hr);
fflush(stderr);
// Clean up the composition objects and swap chain
if (dcompVisual_) { dcompVisual_->Release(); dcompVisual_ = nullptr; }
if (dcompTarget_) { dcompTarget_->Release(); dcompTarget_ = nullptr; }
if (dcompDevice_) { dcompDevice_->Release(); dcompDevice_ = nullptr; }
swapChain_->Release();
swapChain_ = nullptr;
}
} else {
DEBUG_LOGF("DX11: CreateSwapChainForComposition failed (0x%08lx)\n", hr);
}
// Fallback: standard HWND swap chain (no alpha transparency)
if (!swapChain_) {
sd.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
sd.Width = 0; // Auto-detect
sd.Height = 0;
hr = dxgiFactory->CreateSwapChainForHwnd(
device_,
hwnd,
&sd,
nullptr,
nullptr,
&swapChain_
);
if (SUCCEEDED(hr)) {
DEBUG_LOGF("DX11: HWND swap chain created (opaque, no alpha)\n");
}
}
dxgiFactory->Release();
dxgiDevice->Release();
if (FAILED(hr) || !swapChain_) {
DEBUG_LOGF("DX11: All swap chain creation paths failed\n");
shutdown();
return false;
}
createRenderTarget();
return true;
}
void DX11Context::shutdown()
{
cleanupRenderTarget();
// Release DirectComposition objects
if (dcompVisual_) { dcompVisual_->Release(); dcompVisual_ = nullptr; }
if (dcompTarget_) { dcompTarget_->Release(); dcompTarget_ = nullptr; }
if (dcompDevice_) { dcompDevice_->Release(); dcompDevice_ = nullptr; }
if (swapChain_) {
swapChain_->Release();
swapChain_ = nullptr;
}
if (deviceContext_) {
deviceContext_->Release();
deviceContext_ = nullptr;
}
if (device_) {
device_->Release();
device_ = nullptr;
}
hasAlpha_ = false;
}
void DX11Context::resize(int width, int height)
{
(void)width;
(void)height;
if (!swapChain_ || !deviceContext_) return;
cleanupRenderTarget();
// Unbind the render target from the pipeline — ResizeBuffers requires
// ALL outstanding references to back-buffer resources to be released.
// Without this, ResizeBuffers fails with DXGI_ERROR_INVALID_CALL when
// growing the window (shrinking appears fine because the old larger
// buffer simply gets cropped by DWM).
deviceContext_->OMSetRenderTargets(0, nullptr, nullptr);
deviceContext_->Flush();
// For composition swap chains (CreateSwapChainForComposition),
// passing 0,0 means "keep current size" — NOT auto-detect from HWND.
// We must pass the actual pixel dimensions from GetClientRect.
UINT w = 0, h = 0;
if (hwnd_) {
RECT rc;
GetClientRect(hwnd_, &rc);
w = static_cast<UINT>(rc.right - rc.left);
h = static_cast<UINT>(rc.bottom - rc.top);
}
if (w == 0 || h == 0) return;
HRESULT hr = swapChain_->ResizeBuffers(0, w, h, DXGI_FORMAT_UNKNOWN, 0);
if (FAILED(hr)) {
DEBUG_LOGF("DX11: ResizeBuffers(%u x %u) failed (0x%08lx)\n", w, h, hr);
}
createRenderTarget();
// Commit DirectComposition so it picks up the new buffer size
if (dcompDevice_) {
dcompDevice_->Commit();
}
}
void DX11Context::ensureSize()
{
if (!swapChain_ || !hwnd_) return;
// Query current swap chain buffer dimensions
DXGI_SWAP_CHAIN_DESC1 desc;
if (FAILED(swapChain_->GetDesc1(&desc))) return;
// Query actual HWND client area
RECT rc;
GetClientRect(hwnd_, &rc);
UINT clientW = static_cast<UINT>(rc.right - rc.left);
UINT clientH = static_cast<UINT>(rc.bottom - rc.top);
// Resize only when there's a mismatch
if (clientW > 0 && clientH > 0 &&
(desc.Width != clientW || desc.Height != clientH)) {
resize(static_cast<int>(clientW), static_cast<int>(clientH));
}
}
void DX11Context::clear(float r, float g, float b, float a)
{
if (!deviceContext_ || !renderTargetView_) return;
const float clearColor[4] = { r, g, b, a };
deviceContext_->ClearRenderTargetView(renderTargetView_, clearColor);
}
void DX11Context::present(int vsync)
{
if (!swapChain_) return;
swapChain_->Present(vsync ? 1 : 0, 0);
}
void DX11Context::createRenderTarget()
{
if (!swapChain_ || !device_) return;
ID3D11Texture2D* backBuffer = nullptr;
swapChain_->GetBuffer(0, IID_PPV_ARGS(&backBuffer));
if (backBuffer) {
device_->CreateRenderTargetView(backBuffer, nullptr, &renderTargetView_);
backBuffer->Release();
}
}
void DX11Context::cleanupRenderTarget()
{
if (renderTargetView_) {
renderTargetView_->Release();
renderTargetView_ = nullptr;
}
}
} // namespace platform
} // namespace dragonx
#endif // _WIN32

108
src/platform/dx11_context.h Normal file
View File

@@ -0,0 +1,108 @@
// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
// DirectX 11 Rendering Context for Windows
// Uses DXGI swap chain with premultiplied alpha + DirectComposition
// for true per-pixel transparency with DWM Mica/Acrylic backdrops.
#pragma once
#ifdef _WIN32
#include <d3d11.h>
#include <dxgi1_2.h>
#include <cstdio>
// Forward declarations - DirectComposition interfaces
struct IDCompositionDevice;
struct IDCompositionTarget;
struct IDCompositionVisual;
struct SDL_Window;
namespace dragonx {
namespace platform {
class DX11Context {
public:
DX11Context() = default;
~DX11Context() { shutdown(); }
// Non-copyable
DX11Context(const DX11Context&) = delete;
DX11Context& operator=(const DX11Context&) = delete;
/**
* @brief Initialize D3D11 device and DXGI swap chain with alpha support
* @param window SDL window to create the swap chain for
* @return true on success
*/
bool init(SDL_Window* window);
/**
* @brief Shut down and release all D3D11/DXGI resources
*/
void shutdown();
/**
* @brief Resize the swap chain buffers (call on window resize)
* @param width New width (0 = auto-detect from swap chain)
* @param height New height (0 = auto-detect from swap chain)
*/
void resize(int width, int height);
/**
* @brief Ensure swap chain matches the current HWND client size.
* Call once per frame to guarantee the buffers stay in sync.
* No-op if the sizes already match.
*/
void ensureSize();
/**
* @brief Clear the render target with a color
* @param r Red (0-1)
* @param g Green (0-1)
* @param b Blue (0-1)
* @param a Alpha (0-1), 0 = fully transparent for DWM
*/
void clear(float r, float g, float b, float a);
/**
* @brief Present the frame (swap buffers)
* @param vsync 1 = vsync on, 0 = vsync off
*/
void present(int vsync = 1);
/** @brief Whether premultiplied alpha compositing is active */
bool hasAlphaCompositing() const { return hasAlpha_; }
// Accessors
ID3D11Device* device() const { return device_; }
ID3D11DeviceContext* deviceContext() const { return deviceContext_; }
ID3D11RenderTargetView* renderTargetView() const { return renderTargetView_; }
IDXGISwapChain1* swapChain() const { return swapChain_; }
private:
void createRenderTarget();
void cleanupRenderTarget();
// D3D11 core
ID3D11Device* device_ = nullptr;
ID3D11DeviceContext* deviceContext_ = nullptr;
IDXGISwapChain1* swapChain_ = nullptr;
ID3D11RenderTargetView* renderTargetView_ = nullptr;
// DirectComposition (for premultiplied alpha swap chain presentation)
IDCompositionDevice* dcompDevice_ = nullptr;
IDCompositionTarget* dcompTarget_ = nullptr;
IDCompositionVisual* dcompVisual_ = nullptr;
bool hasAlpha_ = false;
HWND hwnd_ = nullptr;
};
} // namespace platform
} // namespace dragonx
#endif // _WIN32

View File

@@ -0,0 +1,182 @@
// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
#include "windows_backdrop.h"
#ifdef _WIN32
#include <windows.h>
#include <dwmapi.h>
#include <SDL3/SDL.h>
#include <cstdio>
#include "../util/logger.h"
// Link with dwmapi.lib
#pragma comment(lib, "dwmapi.lib")
// DWM attribute values not in older SDK headers
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
#endif
#ifndef DWMWA_SYSTEMBACKDROP_TYPE
#define DWMWA_SYSTEMBACKDROP_TYPE 38
#endif
#ifndef DWMWA_MICA_EFFECT
#define DWMWA_MICA_EFFECT 1029
#endif
// System backdrop types (Windows 11 22H2+)
typedef enum {
DWMSBT_AUTO = 0,
DWMSBT_NONE = 1,
DWMSBT_MAINWINDOW = 2, // Mica
DWMSBT_TRANSIENTWINDOW = 3, // Acrylic
DWMSBT_TABBEDWINDOW = 4 // Mica Alt
} DWM_SYSTEMBACKDROP_TYPE;
namespace dragonx {
namespace platform {
// Helper to get HWND from SDL window
static HWND getHWND(SDL_Window* window) {
if (!window) return nullptr;
SDL_PropertiesID props = SDL_GetWindowProperties(window);
if (props == 0) return nullptr;
return (HWND)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr);
}
WindowsVersionInfo getWindowsVersion() {
WindowsVersionInfo info = {};
// Use RtlGetVersion to get the real version (GetVersionEx is deprecated/lies)
typedef NTSTATUS (WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
if (ntdll) {
RtlGetVersionPtr rtlGetVersion = (RtlGetVersionPtr)GetProcAddress(ntdll, "RtlGetVersion");
if (rtlGetVersion) {
RTL_OSVERSIONINFOW osvi = {};
osvi.dwOSVersionInfoSize = sizeof(osvi);
if (rtlGetVersion(&osvi) == 0) {
info.major = osvi.dwMajorVersion;
info.minor = osvi.dwMinorVersion;
info.build = osvi.dwBuildNumber;
}
}
}
info.isWindows11 = (info.major >= 10 && info.build >= 22000);
info.isWindows10 = (info.major >= 10 && info.build >= 10240);
return info;
}
bool isWindowsBackdropAvailable() {
WindowsVersionInfo ver = getWindowsVersion();
// Backdrop effects require at least Windows 10
return ver.isWindows10;
}
bool enableWindowsBackdrop(SDL_Window* window, WindowsBackdrop type) {
HWND hwnd = getHWND(window);
if (!hwnd) {
DEBUG_LOGF("WindowsBackdrop: Failed to get HWND\n");
return false;
}
WindowsVersionInfo ver = getWindowsVersion();
DEBUG_LOGF("WindowsBackdrop: Windows %d.%d.%d detected\n", ver.major, ver.minor, ver.build);
if (!ver.isWindows10) {
DEBUG_LOGF("WindowsBackdrop: Windows 10+ required\n");
return false;
}
// Enable dark mode for title bar (looks better with acrylic)
BOOL useDarkMode = TRUE;
DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &useDarkMode, sizeof(useDarkMode));
// Auto-detect best backdrop type
if (type == WindowsBackdrop::Auto) {
if (ver.isWindows11 && ver.build >= 22621) {
// Windows 11 22H2+ - use Mica Alt for dark themed apps
type = WindowsBackdrop::MicaAlt;
} else if (ver.isWindows11) {
// Windows 11 21H2 - use Mica
type = WindowsBackdrop::Mica;
} else {
// Windows 10 - use Acrylic
type = WindowsBackdrop::Acrylic;
}
}
// Extend DWM frame into entire client area - required for all backdrop types
// This lets the DWM composition show through where we render with alpha = 0
MARGINS margins = {-1, -1, -1, -1};
DwmExtendFrameIntoClientArea(hwnd, &margins);
HRESULT hr = S_OK;
if (ver.build >= 22621) {
// Windows 11 22H2+ - use DWMWA_SYSTEMBACKDROP_TYPE
DWM_SYSTEMBACKDROP_TYPE backdrop;
switch (type) {
case WindowsBackdrop::Mica:
backdrop = DWMSBT_MAINWINDOW;
DEBUG_LOGF("WindowsBackdrop: Enabling Mica\n");
break;
case WindowsBackdrop::MicaAlt:
backdrop = DWMSBT_TABBEDWINDOW;
DEBUG_LOGF("WindowsBackdrop: Enabling Mica Alt\n");
break;
case WindowsBackdrop::Acrylic:
backdrop = DWMSBT_TRANSIENTWINDOW;
DEBUG_LOGF("WindowsBackdrop: Enabling Acrylic\n");
break;
default:
backdrop = DWMSBT_NONE;
break;
}
hr = DwmSetWindowAttribute(hwnd, DWMWA_SYSTEMBACKDROP_TYPE, &backdrop, sizeof(backdrop));
}
else if (ver.isWindows11) {
// Windows 11 21H2 - use legacy DWMWA_MICA_EFFECT
BOOL enableMica = (type == WindowsBackdrop::Mica || type == WindowsBackdrop::MicaAlt);
hr = DwmSetWindowAttribute(hwnd, DWMWA_MICA_EFFECT, &enableMica, sizeof(enableMica));
DEBUG_LOGF("WindowsBackdrop: Enabling Mica (legacy API)\n");
}
else {
// Windows 10 - frame already extended above, basic DWM transparency
// Note: Full acrylic on Win10 requires undocumented APIs
DEBUG_LOGF("WindowsBackdrop: Using extended frame (Win10)\n");
}
if (SUCCEEDED(hr)) {
DEBUG_LOGF("WindowsBackdrop: Successfully enabled\n");
return true;
} else {
DEBUG_LOGF("WindowsBackdrop: DWM call failed with HRESULT 0x%08lx\n", hr);
return false;
}
}
void disableWindowsBackdrop(SDL_Window* window) {
HWND hwnd = getHWND(window);
if (!hwnd) return;
DWM_SYSTEMBACKDROP_TYPE backdrop = DWMSBT_NONE;
DwmSetWindowAttribute(hwnd, DWMWA_SYSTEMBACKDROP_TYPE, &backdrop, sizeof(backdrop));
MARGINS margins = {0, 0, 0, 0};
DwmExtendFrameIntoClientArea(hwnd, &margins);
}
} // namespace platform
} // namespace dragonx
#endif // _WIN32

View File

@@ -0,0 +1,68 @@
// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
#pragma once
// Windows-specific backdrop blur (Mica/Acrylic) support
// Uses DWM (Desktop Window Manager) APIs available on Windows 10/11
#ifdef _WIN32
#include <SDL3/SDL.h>
namespace dragonx {
namespace platform {
// Backdrop types available on Windows
enum class WindowsBackdrop {
None, // No system backdrop
Mica, // Windows 11 Mica material
MicaAlt, // Windows 11 Mica Alt (darker)
Acrylic, // Windows 10/11 Acrylic (transient)
Auto // Auto-detect best option
};
// Enable Windows system backdrop blur
// Returns true if successfully enabled
bool enableWindowsBackdrop(SDL_Window* window, WindowsBackdrop type = WindowsBackdrop::Auto);
// Disable Windows system backdrop
void disableWindowsBackdrop(SDL_Window* window);
// Check if system backdrop is available
bool isWindowsBackdropAvailable();
// Get Windows version info
struct WindowsVersionInfo {
int major;
int minor;
int build;
bool isWindows11; // Build >= 22000
bool isWindows10; // Build >= 10240
};
WindowsVersionInfo getWindowsVersion();
} // namespace platform
} // namespace dragonx
#else // !_WIN32
// Stub for non-Windows platforms
namespace dragonx {
namespace platform {
enum class WindowsBackdrop { None, Mica, MicaAlt, Acrylic, Auto };
inline bool enableWindowsBackdrop(SDL_Window*, WindowsBackdrop = WindowsBackdrop::Auto) { return false; }
inline void disableWindowsBackdrop(SDL_Window*) {}
inline bool isWindowsBackdropAvailable() { return false; }
struct WindowsVersionInfo { int major = 0; int minor = 0; int build = 0; bool isWindows11 = false; bool isWindows10 = false; };
inline WindowsVersionInfo getWindowsVersion() { return {}; }
} // namespace platform
} // namespace dragonx
#endif // _WIN32