Viewport, Platform: Refresh monitor list (win32, glfw) + avoid calling GetWindowFocus before platform window creation to not require of backend to null-check things inconsistently. (#1542)

This commit is contained in:
omar 2018-04-26 16:07:54 +02:00
parent da70c837da
commit cd51f37fc0
6 changed files with 51 additions and 27 deletions

View File

@ -262,6 +262,9 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- viewport: store per-viewport/monitor DPI in .ini file so an application reload or main window changing DPI on reload can be properly patched for. - viewport: store per-viewport/monitor DPI in .ini file so an application reload or main window changing DPI on reload can be properly patched for.
- viewport: vulkan renderer implementation. - viewport: vulkan renderer implementation.
- viewport: need to clarify how to use GetMousePos() from a user point of view. - viewport: need to clarify how to use GetMousePos() from a user point of view.
- platform: glfw: no support for ImGuiBackendFlags_HasMouseHoveredViewport.
- platform: sdl: no support for ImGuiBackendFlags_HasMouseHoveredViewport. maybe we could use SDL_GetMouseFocus() / SDL_WINDOW_MOUSE_FOCUS if imgui could fallback on its heuristic when NoInputs is set
- platform: sdl: no refresh of monitor/display (SDL doesn't seem to have an event for it).
- inputs: we need an explicit flag about whether the imgui window is focused, to be able to distinguish focused key releases vs alt-tabbing all release behaviors. - inputs: we need an explicit flag about whether the imgui window is focused, to be able to distinguish focused key releases vs alt-tabbing all release behaviors.
- inputs: rework IO system to be able to pass actual ordered/timestamped events. use an event queue? (~#335, #71) - inputs: rework IO system to be able to pass actual ordered/timestamped events. use an event queue? (~#335, #71)

View File

@ -53,10 +53,12 @@ static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown;
static double g_Time = 0.0f; static double g_Time = 0.0f;
static bool g_MouseJustPressed[5] = { false, false, false, false, false }; static bool g_MouseJustPressed[5] = { false, false, false, false, false };
static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_Count_] = { 0 }; static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_Count_] = { 0 };
static bool g_WantUpdateMonitors = true;
// Forward Declarations // Forward Declarations
static void ImGui_ImplGlfw_InitPlatformInterface(); static void ImGui_ImplGlfw_InitPlatformInterface();
static void ImGui_ImplGlfw_ShutdownPlatformInterface(); static void ImGui_ImplGlfw_ShutdownPlatformInterface();
static void ImGui_ImplGlfw_UpdateMonitors();
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data) static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
{ {
@ -271,6 +273,8 @@ void ImGui_ImplGlfw_NewFrame()
glfwGetFramebufferSize(g_Window, &display_w, &display_h); glfwGetFramebufferSize(g_Window, &display_w, &display_h);
io.DisplaySize = ImVec2((float)w, (float)h); io.DisplaySize = ImVec2((float)w, (float)h);
io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0); io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0);
if (g_WantUpdateMonitors)
ImGui_ImplGlfw_UpdateMonitors();
// Setup time step // Setup time step
double current_time = glfwGetTime(); double current_time = glfwGetTime();
@ -562,7 +566,6 @@ static int ImGui_ImplGlfw_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_inst
} }
#endif // GLFW_HAS_VULKAN #endif // GLFW_HAS_VULKAN
// FIXME-PLATFORM: Update monitor list when changed (using glfwSetMonitorCallback?)
// FIXME-PLATFORM: GLFW doesn't export monitor work area (see https://github.com/glfw/glfw/pull/989) // FIXME-PLATFORM: GLFW doesn't export monitor work area (see https://github.com/glfw/glfw/pull/989)
static void ImGui_ImplGlfw_UpdateMonitors() static void ImGui_ImplGlfw_UpdateMonitors()
{ {
@ -586,6 +589,12 @@ static void ImGui_ImplGlfw_UpdateMonitors()
#endif #endif
platform_io.Monitors.push_back(monitor); platform_io.Monitors.push_back(monitor);
} }
g_WantUpdateMonitors = false;
}
static void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
{
g_WantUpdateMonitors = true;
} }
static void ImGui_ImplGlfw_InitPlatformInterface() static void ImGui_ImplGlfw_InitPlatformInterface()
@ -614,7 +623,9 @@ static void ImGui_ImplGlfw_InitPlatformInterface()
platform_io.Platform_SetImeInputPos = ImGui_ImplWin32_SetImeInputPos; platform_io.Platform_SetImeInputPos = ImGui_ImplWin32_SetImeInputPos;
#endif #endif
// Note: monitor callback are broken GLFW 3.2 and earlier (see github.com/glfw/glfw/issues/784)
ImGui_ImplGlfw_UpdateMonitors(); ImGui_ImplGlfw_UpdateMonitors();
glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
// Register main window handle (which is owned by the main application, not by us) // Register main window handle (which is owned by the main application, not by us)
ImGuiViewport* main_viewport = ImGui::GetMainViewport(); ImGuiViewport* main_viewport = ImGui::GetMainViewport();

View File

@ -418,8 +418,7 @@ static void ImGui_ImplSDL2_SetWindowFocus(ImGuiViewport* viewport)
static bool ImGui_ImplSDL2_GetWindowFocus(ImGuiViewport* viewport) static bool ImGui_ImplSDL2_GetWindowFocus(ImGuiViewport* viewport)
{ {
ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData; ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData;
bool focus = (SDL_GetWindowFlags(data->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; return (SDL_GetWindowFlags(data->Window) & SDL_WINDOW_INPUT_FOCUS) != 0;
return focus;
} }
static void ImGui_ImplSDL2_RenderWindow(ImGuiViewport* viewport, void*) static void ImGui_ImplSDL2_RenderWindow(ImGuiViewport* viewport, void*)
@ -452,7 +451,7 @@ static int ImGui_ImplSDL2_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_inst
} }
#endif // SDL_HAS_VULKAN #endif // SDL_HAS_VULKAN
// FIXME-PLATFORM: Update monitor list when changed? // FIXME-PLATFORM: SDL doesn't have an event to notify the application of display/monitor changes
static void ImGui_ImplSDL2_UpdateMonitors() static void ImGui_ImplSDL2_UpdateMonitors()
{ {
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();

View File

@ -8,6 +8,7 @@
#include <tchar.h> #include <tchar.h>
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2018-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2018-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag. // 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag.
// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling). // 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling).
@ -26,10 +27,12 @@ static HWND g_hWnd = 0;
static INT64 g_Time = 0; static INT64 g_Time = 0;
static INT64 g_TicksPerSecond = 0; static INT64 g_TicksPerSecond = 0;
static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_Count_; static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_Count_;
static bool g_WantUpdateMonitors = true;
// Forward Declarations // Forward Declarations
static void ImGui_ImplWin32_InitPlatformInterface(); static void ImGui_ImplWin32_InitPlatformInterface();
static void ImGui_ImplWin32_ShutdownPlatformInterface(); static void ImGui_ImplWin32_ShutdownPlatformInterface();
static void ImGui_ImplWin32_UpdateMonitors();
// Functions // Functions
bool ImGui_ImplWin32_Init(void* hwnd) bool ImGui_ImplWin32_Init(void* hwnd)
@ -159,6 +162,8 @@ void ImGui_ImplWin32_NewFrame()
RECT rect; RECT rect;
::GetClientRect(g_hWnd, &rect); ::GetClientRect(g_hWnd, &rect);
io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top)); io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
if (g_WantUpdateMonitors)
ImGui_ImplWin32_UpdateMonitors();
// Setup time step // Setup time step
INT64 current_time; INT64 current_time;
@ -251,7 +256,7 @@ IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wPa
io.MouseWheelH += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f; io.MouseWheelH += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f;
return 0; return 0;
case WM_MOUSEMOVE: case WM_MOUSEMOVE:
io.MousePos.x = (signed short)(lParam); io.MousePos.x = (signed short)(lParam); // Note: this is used for single-viewport support, but in reality the code in ImGui_ImplWin32_UpdateMousePos() overwrite this.
io.MousePos.y = (signed short)(lParam >> 16); io.MousePos.y = (signed short)(lParam >> 16);
return 0; return 0;
case WM_KEYDOWN: case WM_KEYDOWN:
@ -273,6 +278,9 @@ IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wPa
if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor()) if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor())
return 1; return 1;
return 0; return 0;
case WM_DISPLAYCHANGE:
g_WantUpdateMonitors = true;
return 0;
} }
return 0; return 0;
} }
@ -623,11 +631,11 @@ static BOOL CALLBACK ImGui_ImplWin32_UpdateMonitors_EnumFunc(HMONITOR monitor, H
return TRUE; return TRUE;
} }
// FIXME-PLATFORM: Update monitor list when changed (WM_DISPLAYCHANGE?)
static void ImGui_ImplWin32_UpdateMonitors() static void ImGui_ImplWin32_UpdateMonitors()
{ {
ImGui::GetPlatformIO().Monitors.resize(0); ImGui::GetPlatformIO().Monitors.resize(0);
::EnumDisplayMonitors(NULL, NULL, ImGui_ImplWin32_UpdateMonitors_EnumFunc, NULL); ::EnumDisplayMonitors(NULL, NULL, ImGui_ImplWin32_UpdateMonitors_EnumFunc, NULL);
g_WantUpdateMonitors = false;
} }
static void ImGui_ImplWin32_InitPlatformInterface() static void ImGui_ImplWin32_InitPlatformInterface()

View File

@ -3580,21 +3580,6 @@ void ImGui::UpdatePlatformWindows()
if (!(g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)) if (!(g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsEnable))
return; return;
// Update our implicit z-order knowledge of platform windows, which is used when the back-end cannot provide io.MouseHoveredViewport.
if (g.PlatformIO.Platform_GetWindowFocus)
{
ImGuiViewportP* focused_viewport = NULL;
for (int i = 0; i < g.Viewports.Size && focused_viewport == NULL; i++)
if (g.PlatformIO.Platform_GetWindowFocus(g.Viewports[i]))
focused_viewport = g.Viewports[i];
if (focused_viewport && g.PlatformLastFocusedViewport != focused_viewport->ID)
{
if (focused_viewport->LastFrontMostStampCount != g.WindowsFrontMostStampCount)
focused_viewport->LastFrontMostStampCount = ++g.WindowsFrontMostStampCount;
g.PlatformLastFocusedViewport = focused_viewport->ID;
}
}
// Create/resize/destroy platform windows to match each active viewport. // Create/resize/destroy platform windows to match each active viewport.
// Skip the main viewport (index 0), which is always fully handled by the application! // Skip the main viewport (index 0), which is always fully handled by the application!
for (int i = 1; i < g.Viewports.Size; i++) for (int i = 1; i < g.Viewports.Size; i++)
@ -3631,13 +3616,14 @@ void ImGui::UpdatePlatformWindows()
} }
// Create window // Create window
bool is_new_window = (viewport->PlatformHandle == NULL && viewport->PlatformUserData == NULL && viewport->RendererUserData == NULL); bool is_new_window = (viewport->CreatedPlatformWindow == false);
if (is_new_window && viewport->PlatformHandle == NULL && viewport->PlatformUserData == NULL) if (is_new_window)
g.PlatformIO.Platform_CreateWindow(viewport);
if (is_new_window && viewport->RendererUserData == NULL && g.PlatformIO.Renderer_CreateWindow != NULL)
{ {
g.PlatformIO.Platform_CreateWindow(viewport);
if (g.PlatformIO.Renderer_CreateWindow != NULL)
g.PlatformIO.Renderer_CreateWindow(viewport); g.PlatformIO.Renderer_CreateWindow(viewport);
viewport->RendererLastSize = viewport->Size; viewport->RendererLastSize = viewport->Size;
viewport->CreatedPlatformWindow = true;
} }
// Apply Position and Size (from ImGui to Platform/Renderer back-ends) // Apply Position and Size (from ImGui to Platform/Renderer back-ends)
@ -3682,6 +3668,22 @@ void ImGui::UpdatePlatformWindows()
// Clear request flags // Clear request flags
viewport->PlatformRequestClose = viewport->PlatformRequestMove = viewport->PlatformRequestResize = false; viewport->PlatformRequestClose = viewport->PlatformRequestMove = viewport->PlatformRequestResize = false;
} }
// Update our implicit z-order knowledge of platform windows, which is used when the back-end cannot provide io.MouseHoveredViewport.
if (g.PlatformIO.Platform_GetWindowFocus != NULL)
{
ImGuiViewportP* focused_viewport = NULL;
for (int i = 0; i < g.Viewports.Size && focused_viewport == NULL; i++)
if (g.Viewports[i]->PlatformUserData != NULL || g.Viewports[i]->PlatformHandle != NULL || g.Viewports[i]->CreatedPlatformWindow)
if (g.PlatformIO.Platform_GetWindowFocus(g.Viewports[i]))
focused_viewport = g.Viewports[i];
if (focused_viewport && g.PlatformLastFocusedViewport != focused_viewport->ID)
{
if (focused_viewport->LastFrontMostStampCount != g.WindowsFrontMostStampCount)
focused_viewport->LastFrontMostStampCount = ++g.WindowsFrontMostStampCount;
g.PlatformLastFocusedViewport = focused_viewport->ID;
}
}
} }
// This is a default/basic function for performing the rendering/swap of multiple platform windows. // This is a default/basic function for performing the rendering/swap of multiple platform windows.

View File

@ -515,6 +515,7 @@ struct ImGuiViewportP : public ImGuiViewport
int LastFrontMostStampCount; // Last stamp number from when a window hosted by this viewport was made front-most (by comparing this value between two viewport we have an implicit viewport z-order int LastFrontMostStampCount; // Last stamp number from when a window hosted by this viewport was made front-most (by comparing this value between two viewport we have an implicit viewport z-order
ImGuiID LastNameHash; ImGuiID LastNameHash;
ImVec2 LastPos; ImVec2 LastPos;
bool CreatedPlatformWindow;
float Alpha; // Window opacity (when dragging dockable windows/viewports we make them transparent) float Alpha; // Window opacity (when dragging dockable windows/viewports we make them transparent)
float LastAlpha; float LastAlpha;
int PlatformMonitor; int PlatformMonitor;
@ -524,7 +525,7 @@ struct ImGuiViewportP : public ImGuiViewport
ImDrawDataBuilder DrawDataBuilder; ImDrawDataBuilder DrawDataBuilder;
ImVec2 RendererLastSize; ImVec2 RendererLastSize;
ImGuiViewportP() { Idx = 1; LastFrameActive = LastFrameOverlayDrawList = LastFrontMostStampCount = -1; LastNameHash = 0; Alpha = LastAlpha = 1.0f; PlatformMonitor = INT_MIN; Window = NULL; OverlayDrawList = NULL; RendererLastSize = ImVec2(-1.0f,-1.0f); } ImGuiViewportP() { Idx = 1; LastFrameActive = LastFrameOverlayDrawList = LastFrontMostStampCount = -1; LastNameHash = 0; CreatedPlatformWindow = false; Alpha = LastAlpha = 1.0f; PlatformMonitor = INT_MIN; Window = NULL; OverlayDrawList = NULL; RendererLastSize = ImVec2(-1.0f,-1.0f); }
~ImGuiViewportP() { if (OverlayDrawList) IM_DELETE(OverlayDrawList); } ~ImGuiViewportP() { if (OverlayDrawList) IM_DELETE(OverlayDrawList); }
ImRect GetRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } ImRect GetRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
ImVec2 GetCenter() const{ return ImVec2(Pos.x + Size.x * 0.5f, Pos.y + Size.y * 0.5f); } ImVec2 GetCenter() const{ return ImVec2(Pos.x + Size.x * 0.5f, Pos.y + Size.y * 0.5f); }