ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
59.6k stars 10.16k forks source link

[Mac SDL + OpenGL - Glad] If Monitors are offset from one another then mouse position reported is wrong #2744

Open BraedonWooding opened 5 years ago

BraedonWooding commented 5 years ago

It seems that if on a mac you align the monitors a little offset (attached photo) Screen Shot 2019-08-23 at 7 16 47 pm

Note this even happens if you put it below the monitor (i.e. stacked ontop of each other)

Then the mouse position that is used by imgui is off by the amount the window is offset by. This is a problem inside imgui_impl_sdl.cpp I had a look around and couldn't find any information on previous issues with this. The problem is only with SDL_GetGlobalMouseState the normal SDL_GetMouseState is fine (which is why I think no one has reported it). This makes it seem like its a Mac issue

The fix is relatively simple, it seems that the x coordinate is always represented right and only the y coordinate is off. The fix I applied was to get the current window's display bounds and correct the y position of the cursor by that.

// ~247 imgui_impl_sdl.cpp just below mx -= wx; my -= wy; inside the #if 
int index = SDL_GetWindowDisplayIndex(focused_window);
SDL_Rect rect;
SDL_GetDisplayBounds(index, &rect);
my += rect.y;

I didn't create a PR because I'm concerned this will cause havoc with other systems. I don't know enough about how IMGUI to know if this is expected or not :). My view is that when we get the SDL_GetWindowPosition we expect the screen to be at 0, 0 which it isn't always (i.e. if we misalign them as shown). What is really giving me odd thoughts is how I can't replicate it on the 'x' axis it always gives the right result regardless.

Debug Information
SDL Version: 2.0.9_1
Dear ImGui 1.72b (17202)
--------------------------------
sizeof(size_t): 8, sizeof(ImDrawIdx): 2, sizeof(ImDrawVert): 20
define: __cplusplus=201703
define: __APPLE__
define: __GNUC__=4
define: __clang_version__=8.0.1 (tags/RELEASE_801/final)
--------------------------------
io.BackendPlatformName: imgui_impl_sdl
io.BackendRendererName: imgui_impl_opengl3
io.ConfigFlags: 0x00000000
io.ConfigMacOSXBehaviors
io.ConfigInputTextCursorBlink
io.ConfigWindowsResizeFromEdges
io.BackendFlags: 0x0000000E
 HasMouseCursors
 HasSetMousePos
 RendererHasVtxOffset
--------------------------------
io.Fonts: 1 fonts, Flags: 0x00000000, TexSize: 512,64
io.DisplaySize: 1280.00,720.00
io.DisplayFramebufferScale: 1.00,1.00
--------------------------------
style.WindowPadding: 8.00,8.00
style.WindowBorderSize: 1.00
style.FramePadding: 4.00,3.00
style.FrameRounding: 0.00
style.FrameBorderSize: 0.00
style.ItemSpacing: 8.00,4.00
style.ItemInnerSpacing: 4.00,4.00
ocornut commented 5 years ago

Looks same/related to #2151, thanks for the additional information. Could you specify which version of SDL you are using? Thank you!

BraedonWooding commented 5 years ago

I'm using SDL 2.0.9_1 which is the most recent version of SDL2. It also didn't work with 2.0.8 (I upgraded to see if it was an old bug of SDL2)

tlbtlbtlb commented 4 years ago

I have a similar problem. I'm using Imgui with SDL 2.0.9 on a Mac running Catalina. I have displays arranged like this:

image

and Imgui is unusable for windows in the upper monitor. io.MousePos ends up with negative Y coordinates when the mouse is in the window.

I think the true bug is in SDL, where Cocoa_GetGlobalMouseState (the backend for SDL_GetGlobalMouseState) performs this contortion:

static Uint32
Cocoa_GetGlobalMouseState(int *x, int *y)
{
    const NSUInteger cocoaButtons = [NSEvent pressedMouseButtons];
    const NSPoint cocoaLocation = [NSEvent mouseLocation];

    for (NSScreen *screen in [NSScreen screens]) {
        NSRect frame = [screen frame];
        if (NSMouseInRect(cocoaLocation, frame, NO)) {
            *x = (int) cocoaLocation.x;
            *y = (int) ((frame.origin.y + frame.size.height) - cocoaLocation.y);
            break;
        }
    }
...
}

The code where it searches the screens is because Cocoa reports coordinates starting at the BOTTOM left. So it tries to subtract it from the screen height. But it's wrong on a second monitor, or at least reports numbers incompatible with SDL_GetWindowPosition (which gives the expected negative numbers for the top monitor.)

Turning off g_MouseCanUseGlobalState (which is normally only off on Wayland) works much better.

The whole global mouse thing seems like a questionable idea. Why not just use SDL_GetMouseState?