From f3c9c4780630e284578278c57a69d123d607153b Mon Sep 17 00:00:00 2001 From: Antonis Geralis Date: Tue, 19 Nov 2024 23:30:36 +0200 Subject: [PATCH 1/6] try --- src/raylib/platforms/rcore_desktop_glfw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raylib/platforms/rcore_desktop_glfw.c b/src/raylib/platforms/rcore_desktop_glfw.c index d82471e..50dae3f 100644 --- a/src/raylib/platforms/rcore_desktop_glfw.c +++ b/src/raylib/platforms/rcore_desktop_glfw.c @@ -54,11 +54,11 @@ #include "GLFW/glfw3.h" // GLFW3 library: Windows, OpenGL context and Input management // NOTE: GLFW3 already includes gl.h (OpenGL) headers +#include "../external/win32_clipboard.h" // Support retrieving native window handlers #if defined(_WIN32) typedef void *PVOID; typedef PVOID HANDLE; - #include "../external/win32_clipboard.h" typedef HANDLE HWND; #define GLFW_EXPOSE_NATIVE_WIN32 #define GLFW_NATIVE_INCLUDE_NONE // To avoid some symbols re-definition in windows.h From d29819c3ac339c3d9dbddfa7e6a5ba8687aa3dcc Mon Sep 17 00:00:00 2001 From: Antonis Geralis Date: Tue, 19 Nov 2024 23:39:50 +0200 Subject: [PATCH 2/6] again --- src/raylib.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/src/raylib.nim b/src/raylib.nim index 3f0e802..8279bb3 100644 --- a/src/raylib.nim +++ b/src/raylib.nim @@ -5,6 +5,7 @@ import std/[assertions, paths] const raylibDir = currentSourcePath().Path.parentDir / Path"raylib" {.passC: "-I" & raylibDir.string.} +{.passC: "-I" & string(raylibDir / Path"platforms".} {.passC: "-I" & string(raylibDir / Path"external/glfw/include").} {.passC: "-Wall -D_GNU_SOURCE -Wno-missing-braces -Werror=pointer-arith".} when defined(emscripten): From 3a914d7538b27108eebfe46983d3f921cfdfdbc6 Mon Sep 17 00:00:00 2001 From: Antonis Geralis Date: Tue, 19 Nov 2024 23:41:13 +0200 Subject: [PATCH 3/6] ffs --- src/raylib.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raylib.nim b/src/raylib.nim index 8279bb3..c86bc34 100644 --- a/src/raylib.nim +++ b/src/raylib.nim @@ -5,7 +5,7 @@ import std/[assertions, paths] const raylibDir = currentSourcePath().Path.parentDir / Path"raylib" {.passC: "-I" & raylibDir.string.} -{.passC: "-I" & string(raylibDir / Path"platforms".} +{.passC: "-I" & string(raylibDir / Path"platforms").} {.passC: "-I" & string(raylibDir / Path"external/glfw/include").} {.passC: "-Wall -D_GNU_SOURCE -Wno-missing-braces -Werror=pointer-arith".} when defined(emscripten): From aa8d6f46ecc823efffbabd0c4dddfbeba14c1662 Mon Sep 17 00:00:00 2001 From: Antonis Geralis Date: Tue, 19 Nov 2024 23:46:46 +0200 Subject: [PATCH 4/6] see errors now --- src/raylib.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raylib.nim b/src/raylib.nim index c86bc34..74d04e8 100644 --- a/src/raylib.nim +++ b/src/raylib.nim @@ -2,7 +2,7 @@ from std/strutils import addf, toHex from std/unicode import Rune from std/syncio import writeFile import std/[assertions, paths] -const raylibDir = currentSourcePath().Path.parentDir / Path"raylib" +const raylibDir = Path"." / Path"raylib" {.passC: "-I" & raylibDir.string.} {.passC: "-I" & string(raylibDir / Path"platforms").} From 43f037467f53e6a4d235a624223f6b00f2f07be0 Mon Sep 17 00:00:00 2001 From: Antonis Geralis Date: Tue, 19 Nov 2024 23:50:46 +0200 Subject: [PATCH 5/6] modify source --- src/raylib.nim | 3 +-- src/raylib/config.h | 2 +- src/raylib/platforms/rcore_desktop_glfw.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/raylib.nim b/src/raylib.nim index 74d04e8..3f0e802 100644 --- a/src/raylib.nim +++ b/src/raylib.nim @@ -2,10 +2,9 @@ from std/strutils import addf, toHex from std/unicode import Rune from std/syncio import writeFile import std/[assertions, paths] -const raylibDir = Path"." / Path"raylib" +const raylibDir = currentSourcePath().Path.parentDir / Path"raylib" {.passC: "-I" & raylibDir.string.} -{.passC: "-I" & string(raylibDir / Path"platforms").} {.passC: "-I" & string(raylibDir / Path"external/glfw/include").} {.passC: "-Wall -D_GNU_SOURCE -Wno-missing-braces -Werror=pointer-arith".} when defined(emscripten): diff --git a/src/raylib/config.h b/src/raylib/config.h index 00cdedd..d8f7112 100644 --- a/src/raylib/config.h +++ b/src/raylib/config.h @@ -73,7 +73,7 @@ // Support for clipboard image loading // NOTE: Only working on SDL3, GLFW (Windows) and RGFW (Windows) -#define SUPPORT_CLIPBOARD_IMAGE 0 +#define SUPPORT_CLIPBOARD_IMAGE 1 // NOTE: Clipboard image loading requires support for some image file formats // TODO: Those defines should probably be removed from here, I prefer to let the user manage them diff --git a/src/raylib/platforms/rcore_desktop_glfw.c b/src/raylib/platforms/rcore_desktop_glfw.c index 50dae3f..cc05557 100644 --- a/src/raylib/platforms/rcore_desktop_glfw.c +++ b/src/raylib/platforms/rcore_desktop_glfw.c @@ -54,11 +54,11 @@ #include "GLFW/glfw3.h" // GLFW3 library: Windows, OpenGL context and Input management // NOTE: GLFW3 already includes gl.h (OpenGL) headers -#include "../external/win32_clipboard.h" // Support retrieving native window handlers #if defined(_WIN32) typedef void *PVOID; typedef PVOID HANDLE; + #include "external/win32_clipboard.h" typedef HANDLE HWND; #define GLFW_EXPOSE_NATIVE_WIN32 #define GLFW_NATIVE_INCLUDE_NONE // To avoid some symbols re-definition in windows.h From 31f4e974e1728eebdb195bec3eed82318243b206 Mon Sep 17 00:00:00 2001 From: Antonis Geralis Date: Wed, 20 Nov 2024 00:07:52 +0200 Subject: [PATCH 6/6] Add untracked file --- src/raylib/external/win32_clipboard.h | 374 ++++++++++++++++++++++ src/raylib/platforms/rcore_desktop_glfw.c | 2 +- 2 files changed, 375 insertions(+), 1 deletion(-) create mode 100644 src/raylib/external/win32_clipboard.h diff --git a/src/raylib/external/win32_clipboard.h b/src/raylib/external/win32_clipboard.h new file mode 100644 index 0000000..8328564 --- /dev/null +++ b/src/raylib/external/win32_clipboard.h @@ -0,0 +1,374 @@ +#if !defined(_WIN32) +# error "This module is only made for Windows OS" +#endif + +#ifndef WIN32_CLIPBOARD_ +#define WIN32_CLIPBOARD_ +unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long long int *dataSize); +#endif // WIN32_CLIPBOARD_ + +#ifdef WIN32_CLIPBOARD_IMPLEMENTATION +#include +#include +#include +#include + +// NOTE: These search for architecture is taken from "Windows.h", and it's necessary if we really don't wanna import windows.h +// and still make it compile on msvc, because import indirectly importing "winnt.h" (e.g. ) can cause problems is these are not defined. +#if !defined(_X86_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_IX86) +#define _X86_ +#if !defined(_CHPE_X86_ARM64_) && defined(_M_HYBRID) +#define _CHPE_X86_ARM64_ +#endif +#endif + +#if !defined(_AMD64_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && (defined(_M_AMD64) || defined(_M_ARM64EC)) +#define _AMD64_ +#endif + +#if !defined(_ARM_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_ARM) +#define _ARM_ +#endif + +#if !defined(_ARM64_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64EC_) && defined(_M_ARM64) +#define _ARM64_ +#endif + +#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_ARM64EC) +#define _ARM64EC_ +#endif + +#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_M68K) +#define _68K_ +#endif + +#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_MPPC) +#define _MPPC_ +#endif + +#if !defined(_IA64_) && !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_M_IX86) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) && !defined(_ARM64EC_) && defined(_M_IA64) +#define _IA64_ +#endif + + +#define WIN32_LEAN_AND_MEAN +// #include +// #include +// #include +#include +// #include + +#ifndef WINAPI +#if defined(_ARM_) +#define WINAPI +#else +#define WINAPI __stdcall +#endif +#endif + +#ifndef WINAPI +#if defined(_ARM_) +#define WINAPI +#else +#define WINAPI __stdcall +#endif +#endif + +#ifndef WINBASEAPI +#ifndef _KERNEL32_ +#define WINBASEAPI DECLSPEC_IMPORT +#else +#define WINBASEAPI +#endif +#endif + +#ifndef WINUSERAPI +#ifndef _USER32_ +#define WINUSERAPI __declspec (dllimport) +#else +#define WINUSERAPI +#endif +#endif + +typedef int WINBOOL; + + + +// typedef HANDLE HGLOBAL; + +#ifndef HWND +#define HWND void* +#endif + + +#if !defined(_WINUSER_) || !defined(WINUSER_ALREADY_INCLUDED) +WINUSERAPI WINBOOL WINAPI OpenClipboard(HWND hWndNewOwner); +WINUSERAPI WINBOOL WINAPI CloseClipboard(VOID); +WINUSERAPI DWORD WINAPI GetClipboardSequenceNumber(VOID); +WINUSERAPI HWND WINAPI GetClipboardOwner(VOID); +WINUSERAPI HWND WINAPI SetClipboardViewer(HWND hWndNewViewer); +WINUSERAPI HWND WINAPI GetClipboardViewer(VOID); +WINUSERAPI WINBOOL WINAPI ChangeClipboardChain(HWND hWndRemove, HWND hWndNewNext); +WINUSERAPI HANDLE WINAPI SetClipboardData(UINT uFormat, HANDLE hMem); +WINUSERAPI HANDLE WINAPI GetClipboardData(UINT uFormat); +WINUSERAPI UINT WINAPI RegisterClipboardFormatA(LPCSTR lpszFormat); +WINUSERAPI UINT WINAPI RegisterClipboardFormatW(LPCWSTR lpszFormat); +WINUSERAPI int WINAPI CountClipboardFormats(VOID); +WINUSERAPI UINT WINAPI EnumClipboardFormats(UINT format); +WINUSERAPI int WINAPI GetClipboardFormatNameA(UINT format, LPSTR lpszFormatName, int cchMaxCount); +WINUSERAPI int WINAPI GetClipboardFormatNameW(UINT format, LPWSTR lpszFormatName, int cchMaxCount); +WINUSERAPI WINBOOL WINAPI EmptyClipboard(VOID); +WINUSERAPI WINBOOL WINAPI IsClipboardFormatAvailable(UINT format); +WINUSERAPI int WINAPI GetPriorityClipboardFormat(UINT *paFormatPriorityList, int cFormats); +WINUSERAPI HWND WINAPI GetOpenClipboardWindow(VOID); +#endif + +#ifndef HGLOBAL +#define HGLOBAL void* +#endif + +#if !defined(_WINBASE_) || !defined(WINBASE_ALREADY_INCLUDED) +WINBASEAPI SIZE_T WINAPI GlobalSize (HGLOBAL hMem); +WINBASEAPI LPVOID WINAPI GlobalLock (HGLOBAL hMem); +WINBASEAPI WINBOOL WINAPI GlobalUnlock (HGLOBAL hMem); +#endif + + +#if !defined(_WINGDI_) || !defined(WINGDI_ALREADY_INCLUDED) +#ifndef BITMAPINFOHEADER_ALREADY_DEFINED +#define BITMAPINFOHEADER_ALREADY_DEFINED +// Does this header need to be packed ? by the windowps header it doesnt seem to be +#pragma pack(push, 1) +typedef struct tagBITMAPINFOHEADER { + DWORD biSize; + LONG biWidth; + LONG biHeight; + WORD biPlanes; + WORD biBitCount; + DWORD biCompression; + DWORD biSizeImage; + LONG biXPelsPerMeter; + LONG biYPelsPerMeter; + DWORD biClrUsed; + DWORD biClrImportant; +} BITMAPINFOHEADER,*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER; +#pragma pack(pop) +#endif + +#ifndef BITMAPFILEHEADER_ALREADY_DEFINED +#define BITMAPFILEHEADER_ALREADY_DEFINED +#pragma pack(push, 1) +typedef struct tagBITMAPFILEHEADER { + WORD bfType; + DWORD bfSize; + WORD bfReserved1; + WORD bfReserved2; + DWORD bfOffBits; +} BITMAPFILEHEADER,*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER; +#pragma pack(pop) +#endif + +#ifndef RGBQUAD_ALREADY_DEFINED +#define RGBQUAD_ALREADY_DEFINED +typedef struct tagRGBQUAD { + BYTE rgbBlue; + BYTE rgbGreen; + BYTE rgbRed; + BYTE rgbReserved; +} RGBQUAD, *LPRGBQUAD; +#endif + + +// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/4e588f70-bd92-4a6f-b77f-35d0feaf7a57 +#define BI_RGB 0x0000 +#define BI_RLE8 0x0001 +#define BI_RLE4 0x0002 +#define BI_BITFIELDS 0x0003 +#define BI_JPEG 0x0004 +#define BI_PNG 0x0005 +#define BI_CMYK 0x000B +#define BI_CMYKRLE8 0x000C +#define BI_CMYKRLE4 0x000D + +#endif + +// https://learn.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats +#define CF_DIB 8 + +// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setsystemcursor +// #define OCR_NORMAL 32512 // Normal select +// #define OCR_IBEAM 32513 // Text select +// #define OCR_WAIT 32514 // Busy +// #define OCR_CROSS 32515 // Precision select +// #define OCR_UP 32516 // Alternate select +// #define OCR_SIZENWSE 32642 // Diagonal resize 1 +// #define OCR_SIZENESW 32643 // Diagonal resize 2 +// #define OCR_SIZEWE 32644 // Horizontal resize +// #define OCR_SIZENS 32645 // Vertical resize +// #define OCR_SIZEALL 32646 // Move +// #define OCR_NO 32648 // Unavailable +// #define OCR_HAND 32649 // Link select +// #define OCR_APPSTARTING 32650 // + + +//---------------------------------------------------------------------------------- +// Module Internal Functions Declaration +//---------------------------------------------------------------------------------- + + +static BOOL OpenClipboardRetrying(HWND handle); // Open clipboard with a number of retries +static int GetPixelDataOffset(BITMAPINFOHEADER bih); + +unsigned char* Win32GetClipboardImageData(int* width, int* height, unsigned long long int *dataSize) +{ + HWND win = NULL; // Get from somewhere but is doesnt seem to matter + const char* msgString = ""; + int severity = LOG_INFO; + BYTE* bmpData = NULL; + if (!OpenClipboardRetrying(win)) { + severity = LOG_ERROR; + msgString = "Couldn't open clipboard"; + goto end; + } + + HGLOBAL clipHandle = (HGLOBAL)GetClipboardData(CF_DIB); + if (!clipHandle) { + severity = LOG_ERROR; + msgString = "Clipboard data is not an Image"; + goto close; + } + + BITMAPINFOHEADER *bmpInfoHeader = (BITMAPINFOHEADER *)GlobalLock(clipHandle); + if (!bmpInfoHeader) { + // Mapping from HGLOBAL to our local *address space* failed + severity = LOG_ERROR; + msgString = "Clipboard data failed to be locked"; + goto unlock; + } + + *width = bmpInfoHeader->biWidth; + *height = bmpInfoHeader->biHeight; + + SIZE_T clipDataSize = GlobalSize(clipHandle); + if (clipDataSize < sizeof(BITMAPINFOHEADER)) { + // Format CF_DIB needs space for BITMAPINFOHEADER struct. + msgString = "Clipboard has Malformed data"; + severity = LOG_ERROR; + goto unlock; + } + + // Denotes where the pixel data starts from the bmpInfoHeader pointer + int pixelOffset = GetPixelDataOffset(*bmpInfoHeader); + + //--------------------------------------------------------------------------------// + // + // The rest of the section is about create the bytes for a correct BMP file + // Then we copy the data and to a pointer + // + //--------------------------------------------------------------------------------// + + BITMAPFILEHEADER bmpFileHeader = {0}; + SIZE_T bmpFileSize = sizeof(bmpFileHeader) + clipDataSize; + *dataSize = bmpFileSize; + + bmpFileHeader.bfType = 0x4D42; //https://stackoverflow.com/questions/601430/multibyte-character-constants-and-bitmap-file-header-type-constants#601536 + + bmpFileHeader.bfSize = (DWORD)bmpFileSize; // Up to 4GB works fine + bmpFileHeader.bfOffBits = sizeof(bmpFileHeader) + pixelOffset; + + // + // Each process has a default heap provided by the system + // Memory objects allocated by GlobalAlloc and LocalAlloc are in private, + // committed pages with read/write access that cannot be accessed by other processes. + // + // This may be wrong since we might be allocating in a DLL and freeing from another module, the main application + // that may cause heap corruption. We could create a FreeImage function + // + bmpData = malloc(sizeof(bmpFileHeader) + clipDataSize); + // First we add the header for a bmp file + memcpy(bmpData, &bmpFileHeader, sizeof(bmpFileHeader)); + // Then we add the header for the bmp itself + the pixel data + memcpy(bmpData + sizeof(bmpFileHeader), bmpInfoHeader, clipDataSize); + msgString = "Clipboad image acquired successfully"; + + +unlock: + GlobalUnlock(clipHandle); +close: + CloseClipboard(); +end: + + TRACELOG(severity, msgString); + return bmpData; +} + +static BOOL OpenClipboardRetrying(HWND hWnd) +{ + static const int maxTries = 20; + static const int sleepTimeMS = 60; + for (int _ = 0; _ < maxTries; ++_) + { + // Might be being hold by another process + // Or yourself forgot to CloseClipboard + if (OpenClipboard(hWnd)) { + return true; + } + Sleep(sleepTimeMS); + } + return false; +} + +// Based off of researching microsoft docs and reponses from this question https://stackoverflow.com/questions/30552255/how-to-read-a-bitmap-from-the-windows-clipboard#30552856 +// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader +// Get the byte offset where does the pixels data start (from a packed DIB) +static int GetPixelDataOffset(BITMAPINFOHEADER bih) +{ + int offset = 0; + const unsigned int rgbaSize = sizeof(RGBQUAD); + + // biSize Specifies the number of bytes required by the structure + // We expect to always be 40 because it should be packed + if (40 == bih.biSize && 40 == sizeof(BITMAPINFOHEADER)) + { + // + // biBitCount Specifies the number of bits per pixel. + // Might exist some bit masks *after* the header and *before* the pixel offset + // we're looking, but only if we have more than + // 8 bits per pixel, so we need to ajust for that + // + if (bih.biBitCount > 8) + { + // if bih.biCompression is RBG we should NOT offset more + + if (bih.biCompression == BI_BITFIELDS) + { + offset += 3 * rgbaSize; + } else if (bih.biCompression == 6 /* BI_ALPHABITFIELDS */) + { + // Not widely supported, but valid. + offset += 4 * rgbaSize; + } + } + } + + // + // biClrUsed Specifies the number of color indices in the color table that are actually used by the bitmap. + // If this value is zero, the bitmap uses the maximum number of colors + // corresponding to the value of the biBitCount member for the compression mode specified by biCompression. + // If biClrUsed is nonzero and the biBitCount member is less than 16 + // the biClrUsed member specifies the actual number of colors + // + if (bih.biClrUsed > 0) { + offset += bih.biClrUsed * rgbaSize; + } else { + if (bih.biBitCount < 16) + { + offset = offset + (rgbaSize << bih.biBitCount); + } + } + + return bih.biSize + offset; +} +#endif // WIN32_CLIPBOARD_IMPLEMENTATION +// EOF + diff --git a/src/raylib/platforms/rcore_desktop_glfw.c b/src/raylib/platforms/rcore_desktop_glfw.c index cc05557..d82471e 100644 --- a/src/raylib/platforms/rcore_desktop_glfw.c +++ b/src/raylib/platforms/rcore_desktop_glfw.c @@ -58,7 +58,7 @@ #if defined(_WIN32) typedef void *PVOID; typedef PVOID HANDLE; - #include "external/win32_clipboard.h" + #include "../external/win32_clipboard.h" typedef HANDLE HWND; #define GLFW_EXPOSE_NATIVE_WIN32 #define GLFW_NATIVE_INCLUDE_NONE // To avoid some symbols re-definition in windows.h