imgui icon indicating copy to clipboard operation
imgui copied to clipboard

Checking if window has focus doesn't take into consideration other OS windows

Open meemknight opened this issue 1 year ago • 5 comments

ImGui::IsWindowFocused(); 

Returns if the window is the current ImGui window that has focus but doesn't take into consideration if it is focus in regard to other running apps. I don't have a problem with the way it is made but is there a way to check if that window is also the current focused os window?

Is there a way to do something like this?

ImGui::IsWindowFocused() &&  IsWindowFocused(GetCurrentOsWindowFromCurrentImguiWindow());

meemknight avatar Nov 12 '22 08:11 meemknight

Correct, IsWindowFocused is checking if a window is focused from the perspective of Dear ImGui. It doesn't take anything else into consideration.

Edit: See Omar's comment below.

~~Checking whether your app has focus is platform-specific and since you didn't fill out the issue template we can't know what platform you're on. (Either way it's outside the scope of what's relevant on this repo.)~~

~~That being said, if you're on Windows you can check if any of your app's windows have focus using GetActiveWindow() != NULL on the UI thread.~~

PathogenDavid avatar Nov 12 '22 10:11 PathogenDavid

As an undocumented thing, we maintain io.AppFocusLost on modern backends, we could probably rename it to io.AppHasFocus which is easier to digest and make it a documented ?

ocornut avatar Nov 12 '22 11:11 ocornut

I stand corrected! Totally forgot backends handled focus events.

PathogenDavid avatar Nov 12 '22 13:11 PathogenDavid

will appFocusLost be true for all unfoused windows? Changing it to io.AppHasFocus seems like a useful feature

Also is the io different for each window? Like if I use docking Imgui will it work for secondary windows? Or it just checks focus for the main window? I would want a way to check the focus for the current Imgui window regardless if it is docked in the main window or not.

meemknight avatar Nov 14 '22 08:11 meemknight

This will be focus of the whole app aka the main window or any secondary dear imgui viewport.

To check OS focus for one specific viewport you may obtain the ImGuiViewport* and call bool GetPlatformIO().Platform_GetWindowFocus(viewport);

ocornut avatar Nov 14 '22 09:11 ocornut

Hm I don't know if I am doing anything wrong here but it seems to crash when moving the window outside the main window

ImGuiViewport *viewPort = ImGui::GetWindowViewport();
auto io = ImGui::GetIO();
windowInput.hasFocus = ImGui::GetPlatformIO().Platform_GetWindowFocus(viewPort) && !io.AppFocusLost;

image

platformUserData is null

meemknight avatar Nov 16 '22 09:11 meemknight

but it seems to crash when moving the window outside the main window

Happens on the first frame of a new viewport, as Platform_CreateWindow() hasn't been called yet. Internally we prefix our calls with this check:

if (viewport->PlatformWindowCreated)
    if (g.PlatformIO.Platform_GetWindowFocus(viewport))
        ....
  • I pushed d2f9c5d to move PlatformWindowCreated from private ImGuiViewportP to public ImGuiViewport
  • Or instead if (viewport->PlatformUserData != NULL && g.PlatformIO.Platform_GetWindowFocus(viewport))

Right now it's not reasonable to move that responsibility from caller to backend because it would encourage "silently fail" behavior which I dislike.

ocornut avatar Nov 24 '22 15:11 ocornut

I have now tried to add io.AppFocused but:

  • io.AppFocusLost is still needed as a trigger to allow app/engine to do custom clearing/cancelling operation. That's fine we can keep it!
  • io.AddFocused (== current state) cannot be reliably implemented as we don't have the INITIAL app state sent: neither Win32 nor SDL backends are generating an initial io.AddFocusEvent() event on window creating. Defaulting to true would be technically incorrect. I'd prefer to not add it and instead let you do the polling for now.

ocornut avatar Nov 24 '22 15:11 ocornut

Closing this for now as I believe calling Platform_GetWindowFocus() answers the question.

I believe there are possibilities that:

  • We add a bool Focused flag to ImGuiViewport eventually (even on master). Currently we can only get this reliably on docking branch.
  • We add an additional flag to IsWindowFocused() to check the platform/native state.

If this change we'll post here.

ocornut avatar Nov 24 '22 16:11 ocornut

thank you, I'll look into it.

meemknight avatar Nov 26 '22 09:11 meemknight

calling Platform_GetWindowFocus() answers the question.

Could you please provide an example. I am trying to run with no success:

platformIO.Platform_GetWindowFocus(viewport) crashes ImGui.

    ImGuiPlatformIO& platformIO = ImGui::GetPlatformIO();
    ImGuiViewport* viewport = ImGui::GetMainViewport();

    if (viewport->PlatformWindowCreated)
        if (platformIO.Platform_GetWindowFocus(viewport))
            ImGui::Text("platformIO.Platform_GetWindowFocus(viewport) %d",
                         platformIO.Platform_GetWindowFocus(viewport));
                         

OneArb avatar Mar 18 '23 20:03 OneArb

@OneArb The platform IO functions are provided by the backend.

If ImGuiConfigFlags_ViewportsEnable is not set during backend initialization those functions will not be provided.

PathogenDavid avatar Mar 20 '23 14:03 PathogenDavid

@PathogenDavid Thanks.

That presumes I would be using a default backend from the examples/ folder:

I believe that is not the case as I am running the orx ImGui implementation.

When I set io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable, I get core dumped. I am running 1.89.3 docking build, GLFW 3.3.

I do not actually need to check OS focus within a specific viewport, but rather check if there is focus on the whole app level.

io.AppFocusLost is probably what I want?

I am just trying to throttle down the framerate to lower consumption for gaming laptops when hovering away from ImGui or switching app.

io.AddFocusEvent(focus); seems the way but I'd need an example on how to pull that event from the queue.

OneArb avatar Mar 20 '23 20:03 OneArb

@OneArb Yeah, the backend must support viewports. (It's odd you got core dumped, but maybe your backend is barfing on something with viewports enabled.)

ImGuiIO::AppFocusLost does sound like what you want, but keep in mind it requires support from the backend as well.

I'd need an example on how to pull that event from the queue.

Calling AddFocusEvent is what drives the value of AppFocusLost. Ut's meant to be called from the backend.

If you're using thegwydd/ImGuiOrx, it does not appear that it supports focus events. (Or the modern input queue at all -- it's quite dated.)


You might be better off approaching this from an Orx angle rather than a Dear ImGui one. Dear ImGui doesn't really know anything about operating system windows, apps, or app focus. Those responsibilities fall on the backend.

If you have access to the GLFWwindow* used by your app, you should be able to install a focus callback with glfwSetWindowFocusCallback.

You might need to chain-call the original callback if Orx installed one of its own. You can see examples of how to do this by searching for PrevUserCallbackWindowFocus in imgui_impl_glfw.cpp.

PathogenDavid avatar Mar 20 '23 22:03 PathogenDavid