Skip to content

Commit

Permalink
Added test for ocornut#4029
Browse files Browse the repository at this point in the history
  • Loading branch information
PathogenDavid committed Apr 10, 2021
1 parent d6a5cc7 commit 391df2b
Show file tree
Hide file tree
Showing 4 changed files with 199 additions and 2 deletions.
5 changes: 5 additions & 0 deletions backends/imgui_impl_glfw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ static GLFWscrollfun g_PrevUserCallbackScroll = NULL;
static GLFWkeyfun g_PrevUserCallbackKey = NULL;
static GLFWcharfun g_PrevUserCallbackChar = NULL;

IMGUI_IMPL_API void* __HACK__GetNativeWindowHandle()
{
return g_Window != nullptr ? glfwGetWin32Window(g_Window) : nullptr;
}

static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
{
return glfwGetClipboardString((GLFWwindow*)user_data);
Expand Down
2 changes: 2 additions & 0 deletions backends/imgui_impl_glfw.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, i
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);

IMGUI_IMPL_API void* __HACK__GetNativeWindowHandle();
4 changes: 2 additions & 2 deletions examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v110</PlatformToolset>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
Expand Down Expand Up @@ -181,4 +181,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
190 changes: 190 additions & 0 deletions examples/example_glfw_opengl3/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,193 @@ static void glfw_error_callback(int error, const char* description)
fprintf(stderr, "Glfw Error %d: %s\n", error, description);
}

#include<Windows.h>
struct GLFWwindow;
HWND glfwGetWin32Window(GLFWwindow* window);

static void GH4029_AddLocale();

static void GH4029_DoTest(bool pedanticLineEndings, bool explicitLocale)
{
printf("==================================================\n");
printf("Clipboard test %d, %d\n", pedanticLineEndings, explicitLocale);
printf("==================================================\n");

// Open the clipboard
printf("Opening the clipboard...\n");
HWND windowHandle = (HWND)__HACK__GetNativeWindowHandle();
if (windowHandle == nullptr)
{
printf("Failed to get HWND from GLFW backend.\n");
return;
}

if (!OpenClipboard(windowHandle))
{
printf("Failed to open clipboard. Error %d\n", GetLastError());
return;
}

// Empty the clipboard's current contents
printf("Emptying the clipboard...\n");
if (!EmptyClipboard())
{
printf("Failed to empty clipboard. Error %d\n", GetLastError());
CloseClipboard();
return;
}

// Allocate a buffer for the text
printf("Allocating the clipboard buffer...\n");
const wchar_t* text = pedanticLineEndings ? L"111111111111111111111111111111111\r\n" : L"111111111111111111111111111111111\n";
size_t charCount = wcslen(text) + 1; // +1 for null terminator
size_t byteCount = charCount * sizeof(wchar_t);

HGLOBAL bufferHandle = GlobalAlloc(GMEM_MOVEABLE, byteCount);
if (bufferHandle == nullptr)
{
printf("Failed to allocate clipboard buffer. Error %d\n", GetLastError());
CloseClipboard();
return;
}

// Populate the buffer
printf("Populating the clipboard buffer...\n");
void* buffer = GlobalLock(bufferHandle);
if (buffer == nullptr)
{
printf("Failed to lock the clipboard buffer. Error %d\n", GetLastError());
GlobalFree(bufferHandle);
CloseClipboard();
return;
}

errno_t error = wcscpy_s((wchar_t*)buffer, charCount + 1, text);
if (error != 0)
{
printf("Failed to copy the string to the buffer. Error %d\n", error);
GlobalFree(bufferHandle);
CloseClipboard();
return;
}

BOOL stillLocked = GlobalUnlock(bufferHandle);
if (stillLocked || GetLastError() != NO_ERROR)
{
printf("Failed to unlock the clipboard buffer. Error %d Still locked? %s\n", GetLastError(), stillLocked ? "Yes" : "No");
GlobalFree(bufferHandle);
CloseClipboard();
return;
}

// Set the clipboard data
printf("Setting the clipboard data...\n");
HGLOBAL setHandle = SetClipboardData(CF_UNICODETEXT, bufferHandle);
if (setHandle == nullptr)
{
printf("Failed to set clipboard buffer. Error %d\n", GetLastError());
GlobalFree(bufferHandle);
CloseClipboard();
return;
}
else if (setHandle != bufferHandle)
{
// This should not happen. I think the intent of returning the buffer is just to support delayed clipboard rendering.
// (Although that doesn't seem like it'd be very "delayed".)
printf("Windows returned the wrong clipboard buffer handle??? Error %d\n", GetLastError());
}

// Add the locale if requested
if (explicitLocale)
{
printf("Adding locale ID...\n");
GH4029_AddLocale();
}

// Close the clipboard
if (!CloseClipboard())
{
printf("Failed to close the clipboard.\n");
}

printf("Done!\n");
}

static void GH4029_AddLocale()
{
// Allocate a buffer for the locale ID
HGLOBAL bufferHandle = GlobalAlloc(GMEM_MOVEABLE, sizeof(LCID));
if (bufferHandle == nullptr)
{
printf("Failed to allocate locale ID buffer. Error %d\n", GetLastError());
return;
}

// Populate the buffer
LCID* localeId = (LCID*)GlobalLock(bufferHandle);
if (localeId == nullptr)
{
printf("Failed to lock the locale ID buffer. Error %d\n", GetLastError());
GlobalFree(bufferHandle);
return;
}

*localeId = LOCALE_INVARIANT;

BOOL stillLocked = GlobalUnlock(bufferHandle);
if (stillLocked || GetLastError() != NO_ERROR)
{
printf("Failed to unlock the locale ID buffer. Error %d Still locked? %s\n", GetLastError(), stillLocked ? "Yes" : "No");
GlobalFree(bufferHandle);
return;
}

// Set the clipboard data
HGLOBAL setHandle = SetClipboardData(CF_LOCALE, bufferHandle);
if (setHandle == nullptr)
{
printf("Failed to set locale ID buffer. Error %d\n", GetLastError());
GlobalFree(bufferHandle);
return;
}
else if (setHandle != bufferHandle)
{
// This should not happen. I think the intent of returning the buffer is just to support delayed clipboard rendering.
// (Although that doesn't seem like it'd be very "delayed".)
printf("Windows returned the wrong locale ID buffer handle??? Error %d\n", GetLastError());
return;
}

printf("Successfully populated the locale ID.\n");
}

static void GH4029()
{
ImGui::Begin("GH-4029 Clipboard Issue Test");

if (ImGui::Button("Run test 00"))
{
GH4029_DoTest(false, false);
}

if (ImGui::Button("Run test 01"))
{
GH4029_DoTest(false, true);
}

if (ImGui::Button("Run test 10"))
{
GH4029_DoTest(true, false);
}

if (ImGui::Button("Run test 11"))
{
GH4029_DoTest(true, true);
}

ImGui::End();
}

int main(int, char**)
{
// Setup window
Expand Down Expand Up @@ -199,6 +386,9 @@ int main(int, char**)
ImGui::End();
}

// Show GH-4029 test window
GH4029();

// Rendering
ImGui::Render();
int display_w, display_h;
Expand Down

0 comments on commit 391df2b

Please sign in to comment.