Backends: moved global to a data structure to facilitate support for multi-contexts. (#586, #1851, #2004, #3012, #3934, #4141)

This is NOT enable multi-contexts for any backends
- in order to make this commit as harmless as possible, while containing all the cruft/renaming
-
This commit is contained in:
ocornut
2021-06-28 16:52:10 +02:00
parent 88f4c1321a
commit 70c603854e
12 changed files with 1042 additions and 705 deletions

View File

@ -18,6 +18,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2021-03-22: Rework global mouse pos availability check listing supported platforms explicitly, effectively fixing mouse access on Raspberry Pi. (#2837, #3950)
// 2020-05-25: Misc: Report a zero display-size when window is minimized, to be consistent with other backends.
// 2020-02-20: Inputs: Fixed mapping for ImGuiKey_KeyPadEnter (using SDL_SCANCODE_KP_ENTER instead of SDL_SCANCODE_RETURN2).
@ -59,20 +60,32 @@
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE SDL_VERSION_ATLEAST(2,0,4)
#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6)
// Data
static SDL_Window* g_Window = NULL;
static Uint64 g_Time = 0;
static bool g_MousePressed[3] = { false, false, false };
static SDL_Cursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
static char* g_ClipboardTextData = NULL;
static bool g_MouseCanUseGlobalState = true;
struct ImGui_ImplSDL2_Data
{
SDL_Window* Window;
Uint64 Time;
bool MousePressed[3];
SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT];
char* ClipboardTextData;
bool MouseCanUseGlobalState;
ImGui_ImplSDL2_Data() { memset(this, 0, sizeof(*this)); }
};
// Wrapping access to backend data data (to facilitate multiple-contexts stored in io.BackendPlatformUserData)
static ImGui_ImplSDL2_Data* g_Data;
static ImGui_ImplSDL2_Data* ImGui_ImplSDL2_CreateBackendData() { IM_ASSERT(g_Data == NULL); g_Data = IM_NEW(ImGui_ImplSDL2_Data); return g_Data; }
static ImGui_ImplSDL2_Data* ImGui_ImplSDL2_GetBackendData() { return ImGui::GetCurrentContext() != NULL ? g_Data : NULL; }
static void ImGui_ImplSDL2_DestroyBackendData() { IM_DELETE(g_Data); g_Data = NULL; }
// Functions
static const char* ImGui_ImplSDL2_GetClipboardText(void*)
{
if (g_ClipboardTextData)
SDL_free(g_ClipboardTextData);
g_ClipboardTextData = SDL_GetClipboardText();
return g_ClipboardTextData;
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
if (bd->ClipboardTextData)
SDL_free(bd->ClipboardTextData);
bd->ClipboardTextData = SDL_GetClipboardText();
return bd->ClipboardTextData;
}
static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text)
@ -88,6 +101,8 @@ static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text)
bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
switch (event->type)
{
case SDL_MOUSEWHEEL:
@ -100,9 +115,9 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
}
case SDL_MOUSEBUTTONDOWN:
{
if (event->button.button == SDL_BUTTON_LEFT) g_MousePressed[0] = true;
if (event->button.button == SDL_BUTTON_RIGHT) g_MousePressed[1] = true;
if (event->button.button == SDL_BUTTON_MIDDLE) g_MousePressed[2] = true;
if (event->button.button == SDL_BUTTON_LEFT) { bd->MousePressed[0] = true; }
if (event->button.button == SDL_BUTTON_RIGHT) { bd->MousePressed[1] = true; }
if (event->button.button == SDL_BUTTON_MIDDLE) { bd->MousePressed[2] = true; }
return true;
}
case SDL_TEXTINPUT:
@ -132,13 +147,17 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
static bool ImGui_ImplSDL2_Init(SDL_Window* window)
{
g_Window = window;
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_CreateBackendData();
bd->Window = window;
// Setup backend capabilities flags
ImGuiIO& io = ImGui::GetIO();
io.BackendPlatformUserData = (void*)bd;
io.BackendPlatformName = "imgui_impl_sdl";
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
io.BackendPlatformName = "imgui_impl_sdl";
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB;
@ -169,24 +188,24 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window)
io.ClipboardUserData = NULL;
// Load mouse cursors
g_MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
g_MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
g_MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
g_MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
g_MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO);
bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
bd->MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO);
// Check and store if we are on a SDL backend that supports global mouse position
// ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
const char* sdl_backend = SDL_GetCurrentVideoDriver();
const char* global_mouse_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" };
g_MouseCanUseGlobalState = false;
bd->MouseCanUseGlobalState = false;
for (int n = 0; n < IM_ARRAYSIZE(global_mouse_whitelist); n++)
if (strncmp(sdl_backend, global_mouse_whitelist[n], strlen(global_mouse_whitelist[n])) == 0)
g_MouseCanUseGlobalState = true;
bd->MouseCanUseGlobalState = true;
#ifdef _WIN32
SDL_SysWMinfo wmInfo;
@ -202,7 +221,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window)
bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context)
{
(void)sdl_gl_context; // Viewport branch will need this.
IM_UNUSED(sdl_gl_context); // Viewport branch will need this.
return ImGui_ImplSDL2_Init(window);
}
@ -229,41 +248,48 @@ bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window)
void ImGui_ImplSDL2_Shutdown()
{
g_Window = NULL;
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
bd->Window = NULL;
// Destroy last known clipboard data
if (g_ClipboardTextData)
SDL_free(g_ClipboardTextData);
g_ClipboardTextData = NULL;
if (bd->ClipboardTextData)
SDL_free(bd->ClipboardTextData);
bd->ClipboardTextData = NULL;
// Destroy SDL mouse cursors
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
SDL_FreeCursor(g_MouseCursors[cursor_n]);
memset(g_MouseCursors, 0, sizeof(g_MouseCursors));
SDL_FreeCursor(bd->MouseCursors[cursor_n]);
memset(bd->MouseCursors, 0, sizeof(bd->MouseCursors));
io.BackendPlatformName = NULL;
io.BackendPlatformUserData = NULL;
ImGui_ImplSDL2_DestroyBackendData();
}
static void ImGui_ImplSDL2_UpdateMousePosAndButtons()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
// Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
if (io.WantSetMousePos)
SDL_WarpMouseInWindow(g_Window, (int)io.MousePos.x, (int)io.MousePos.y);
SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y);
else
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
int mx, my;
Uint32 mouse_buttons = SDL_GetMouseState(&mx, &my);
io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[1] = g_MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false;
io.MouseDown[0] = bd->MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[1] = bd->MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
io.MouseDown[2] = bd->MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
bd->MousePressed[0] = bd->MousePressed[1] = bd->MousePressed[2] = false;
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS)
SDL_Window* focused_window = SDL_GetKeyboardFocus();
if (g_Window == focused_window)
if (bd->Window == focused_window)
{
if (g_MouseCanUseGlobalState)
if (bd->MouseCanUseGlobalState)
{
// SDL_GetMouseState() gives mouse position seemingly based on the last window entered/focused(?)
// The creation of a new windows at runtime and SDL_CaptureMouse both seems to severely mess up with that, so we retrieve that position globally.
@ -282,7 +308,7 @@ static void ImGui_ImplSDL2_UpdateMousePosAndButtons()
bool any_mouse_button_down = ImGui::IsAnyMouseDown();
SDL_CaptureMouse(any_mouse_button_down ? SDL_TRUE : SDL_FALSE);
#else
if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS)
if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS)
io.MousePos = ImVec2((float)mx, (float)my);
#endif
}
@ -292,6 +318,7 @@ static void ImGui_ImplSDL2_UpdateMouseCursor()
ImGuiIO& io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
return;
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
@ -302,7 +329,7 @@ static void ImGui_ImplSDL2_UpdateMouseCursor()
else
{
// Show OS mouse cursor
SDL_SetCursor(g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]);
SDL_SetCursor(bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
SDL_ShowCursor(SDL_TRUE);
}
}
@ -351,6 +378,8 @@ static void ImGui_ImplSDL2_UpdateGamepads()
void ImGui_ImplSDL2_NewFrame(SDL_Window* window)
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
IM_ASSERT(bd->Window == window); // FIXME: Should remove parameter from ImGui_ImplSDL2_NewFrame()
// Setup display size (every frame to accommodate for window resizing)
int w, h;
@ -366,8 +395,8 @@ void ImGui_ImplSDL2_NewFrame(SDL_Window* window)
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
static Uint64 frequency = SDL_GetPerformanceFrequency();
Uint64 current_time = SDL_GetPerformanceCounter();
io.DeltaTime = g_Time > 0 ? (float)((double)(current_time - g_Time) / frequency) : (float)(1.0f / 60.0f);
g_Time = current_time;
io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f);
bd->Time = current_time;
ImGui_ImplSDL2_UpdateMousePosAndButtons();
ImGui_ImplSDL2_UpdateMouseCursor();