Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: glfwGetCurrentMonitor #1699

Open
nornagon opened this issue May 24, 2020 · 13 comments
Open

Feature request: glfwGetCurrentMonitor #1699

nornagon opened this issue May 24, 2020 · 13 comments
Assignees
Labels
enhancement Feature suggestions and PRs macOS Wayland Windows Win32 specific (not Cygwin or WSL) X11
Projects

Comments

@nornagon
Copy link

nornagon commented May 24, 2020

macOS and Windows both have some concept of which monitor is "current" when multiple displays are attached.

macOS: [NSScreen main] returns the monitor which contains the window which currently has keyboard focus.
Windows: MonitorFromWindow(GetForegroundWindow()) does the same. (MonitorFromWindow, GetForegroundWindow)

It would be great to be able to get this information through glfw to support the use case of opening a window on the "correct" display.

@DerekCresswell
Copy link

Do you mean glfwGetPrimaryMonitor?

@nornagon
Copy link
Author

That function returns the first monitor in the monitor list, which is not the same as the monitor which the user is currently using.

@elmindreda elmindreda added the enhancement Feature suggestions and PRs label Jun 2, 2020
@elmindreda
Copy link
Member

It would be great to be able to get this information through glfw to support the use case of opening a window on the "correct" display.

Do you mean windowed mode windows, full screen windows or both?

@nornagon
Copy link
Author

nornagon commented Jun 2, 2020

Once the "current" monitor is fetched, it should be possible to open either a fullscreen or a windowed mode window on that monitor. For my particular use case I'm interested in opening a windowed mode window on the current monitor. This API would be a sufficient addition to accomplish that using other monitor geometry querying methods that are already available.

@DerekCresswell
Copy link

DerekCresswell commented Jun 5, 2020

Do I understand correctly, you want to get the monitor a window is on, or "most" on (In the case of it being in between)?

Cause the way I see it, the "monitor" a window is on could be hard to figure out or define.

@nornagon
Copy link
Author

nornagon commented Jun 5, 2020

@DerekCresswell both macOS and Windows have APIs to perform this function, as mentioned in the top post.

@elmindreda elmindreda added macOS Wayland Windows Win32 specific (not Cygwin or WSL) X11 labels Jul 3, 2020
@elmindreda elmindreda self-assigned this Jul 15, 2020
@elmindreda elmindreda added this to Todo in Queue Jul 15, 2020
@elmindreda
Copy link
Member

This would be a useful addition. I propose glfwGetClosestMonitor to (hopefully) help tell it apart from glfwGetWindowMonitor.

@nornagon
Copy link
Author

@elmindreda thanks! IMO Closest implies geometrically closest, which isn't what the mentioned APIs do. Perhaps glfwGetFocusedMonitor?

@slawrence2302
Copy link

Here are a couple functions I have been using to get these behaviors using the existing API. The first gets the monitor the cursor is currently on (get focused monitor?). This requires the window to be created first, but if the window is resized/repositioned immediately after creation it is not even visible in the wrong location before it is moved. The second gets the monitor the window is most on by area (get closest monitor). Note, these are actually translated versions because my original versions further functionalize some of this stuff, so may have some typo bugs.

bool glfw_get_mouse_monitor(
    GLFWmonitor** monitor,
    GLFWwindow* window
) {
    bool success = false;

    double cursor_position[2] = {0};
    glfwGetCursorPos(window, &cursor_position[0], &cursor_position[1]);

    int window_position[2] = {0};
    glfwGetWindowPos(window, &window_position[0], &window_position[1]);

    int monitors_size = 0;
    GLFWmonitor** monitors = glfwGetMonitors(&monitors_size);

    // convert cursor position from window coordinates to screen coordinates
    cursor_position[0] += window_position[0];
    cursor_position[1] += window_position[1];

    for (int i = 0; ((!success) && (i < monitors_size)); ++i)
    {
        int monitor_position[2] = {0};
        glfwGetMonitorPos(monitors[i], &monitor_position[0], &monitor_position[1]);

        const GLFWvidmode* monitor_video_mode = glfwGetVideoMode(monitors[i]);

        if (
            (cursor_position[0] < monitor_position[0]) ||
            (cursor_position[0] > (monitor_position[0] + monitor_video_mode->width)) ||
            (cursor_position[1] < monitor_position[1]) ||
            (cursor_position[1] > (monitor_position[1] + monitor_video_mode->height))
        ) {
            *monitor = monitors[i];
            success = true;
        }
    }

    // true: monitor contains the monitor the mouse is on
    // false: monitor is unmodified
    return success;
}

bool glfw_get_window_monitor(
    GLFWmonitor** monitor,
    GLFWwindow* window
) {
    bool success = false;

    int window_rectangle[4] = {0};
    glfwGetWindowPos(window, &window_rectangle[0], &window_rectangle[1]);
    glfwGetWindowSize(window, &window_rectangle[2], &window_rectangle[3]);

    int monitors_size = 0;
    GLFWmonitor** monitors = glfwGetMonitors(&monitors_size);

    GLFWmonitor* closest_monitor = NULL;
    int max_overlap_area = 0;

    for (int i = 0; i < monitors_size; ++i)
    {
        int monitor_position[2] = {0};
        glfwGetMonitorPos(monitors[i], &monitor_position[0], &monitor_position[1]);

        const GLFWvidmode* monitor_video_mode = glfwGetVideoMode(monitors[i]);

        if (
            !(
                ((window_rectangle[0] + window_rectangle[2]) < monitor_rectangle[0]) ||
                (window_rectangle[0] > (monitor_rectangle[0] + monitor_rectangle[2])) ||
                ((window_rectangle[1] + window_rectangle[3]) < monitor_rectangle[1]) ||
                (window_rectangle[1] > (monitor_rectangle[1] + monitor_rectangle[3]))
            )
        ) {
            int intersection_rectangle[4] = {0};

            // x, width
            if (window_rectangle[0] < monitor_rectangle[0])
            {
                intersection_rectangle[0] = monitor_rectangle[0];

                if ((window_rectangle[0] + window_rectangle[2]) < (monitor_rectangle[0] + monitor_rectangle[2]))
                {
                    intersection_rectangle[2] = (window_rectangle[0] + window_rectangle[2]) - intersection_rectangle[0];
                }
                else
                {
                    intersection_rectangle[2] = monitor_rectangle[2];
                }
            }
            else
            {
                intersection_rectangle[0] = window_rectangle[0];

                if ((monitor_rectangle[0] + monitor_rectangle[2]) < (window_rectangle[0] + window_rectangle[2]))
                {
                    intersection_rectangle[2] = (monitor_rectangle[0] + monitor_rectangle[2]) - intersection_rectangle[0];
                }
                else
                {
                    intersection_rectangle[2] = window_rectangle[2];
                }
            }

            // y, height
            if (window_rectangle[1] < monitor_rectangle[1])
            {
                intersection_rectangle[1] = monitor_rectangle[1];

                if ((window_rectangle[1] + window_rectangle[3]) < (monitor_rectangle[1] + monitor_rectangle[3]))
                {
                    intersection_rectangle[3] = (window_rectangle[1] + window_rectangle[3]) - intersection_rectangle[1];
                }
                else
                {
                    intersection_rectangle[3] = monitor_rectangle[3];
                }
            }
            else
            {
                intersection_rectangle[1] = window_rectangle[1];

                if ((monitor_rectangle[1] + monitor_rectangle[3]) < (window_rectangle[1] + window_rectangle[3]))
                {
                    intersection_rectangle[3] = (monitor_rectangle[1] + monitor_rectangle[3]) - intersection_rectangle[1];
                }
                else
                {
                    intersection_rectangle[3] = window_rectangle[3];
                }
            }

            int overlap_area = intersection_rectangle[3] * intersection_rectangle[4];
            if (overlap_area > max_overlap_area)
            {
                closest_monitor = monitors[i];
                max_overlap_area = overlap_area;
            }
        }
    }

    if (closest_monitor)
    {
        *monitor = closest_monitor;
        success = true;
    }

    // true: monitor contains the monitor the window is most on
    // false: monitor is unmodified
    return success;
}

@nornagon
Copy link
Author

nornagon commented Nov 13, 2020

@slawrence2302 this is a neat workaround, thanks for posting it! FWIW, the proposal I'm making is that glfwGetFocusedMonitor returns the monitor which contains the currently focused window. That is, the window that would receive keyboard input if you pressed a key. This is what [NSScreen main] on macOS and MonitorFromWindow(GetForegroundWindow()) on Windows do. As opposed to your code which uses the mouse cursor position to determine the "current" screen. I think both interpretations are reasonable, but it seems simpler and more consistent with other apps to use the functionality that the OS already provides.

@slawrence2302
Copy link

@nornagon, I thought that might be what you meant, and for the record I would also find that feature useful. Things like start menus (or equivalents) sometimes only being visible on the primary monitor make the cursor solution less than perfect, and I definitely agree that the easiest behavior for the user to understand is the behavior they're already used to.

@endanke
Copy link

endanke commented Jul 19, 2021

This feature would be very useful in cases when you need to create a scaled rendering context using the glfwGetMonitorContentScale on macOS before the window of the application is created.

Is it against the ideas of GLFW to implement functions which are not fully cross-platform? (I guess it's not an issue since we have native access functions.)

Because I think it would be easy to implement glfwGetCurrentMonitor using the platform-specific functions mentioned by @nornagon. If there's no equivalent for Unix-like systems, the function could return null or maybe the result for @slawrence2302's proposed solution.

@kikonen
Copy link

kikonen commented Jan 15, 2024

@slawrence2302
Nice, seems to work fine enough, with small fixes

glfw_get_window_monitor(...)
...
            int monitor_rectangle[4] = {
                monitor_position[0],
                monitor_position[1],
                monitor_video_mode->width,
                monitor_video_mode->height,
            };
...
                int overlap_area = intersection_rectangle[2] * intersection_rectangle[3];

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Feature suggestions and PRs macOS Wayland Windows Win32 specific (not Cygwin or WSL) X11
Projects
Queue
Todo
Development

No branches or pull requests

6 participants