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

Query for desktop work area #920

Open
adambrown opened this Issue Dec 18, 2016 · 14 comments

Comments

Projects
None yet
6 participants
@adambrown

adambrown commented Dec 18, 2016

The screen working area is the desktop area of the display, excluding taskbars, docked windows, and docked tool bars.

In windows you get it with (using System.Windows.Forms):

Screen::WorkingArea

https://msdn.microsoft.com/en-us/library/system.windows.forms.screen.workingarea

In java you get it by subtracting screen insets from screen dimensions for each screen since not all screens have these items on them:

Toolkit.getDefaultToolkit().getScreenInsets(graphicsConfiguration)

I don't know how Java gets them for OSX but it does somehow, possibly someone who knows something about OSX can chime in.

Either method, getting the working area directly, or getting insets and subtracting from screen space works fine, but right now there is no way in GLFW, that I could find, to get this space.

One reason this is necessary is that right now GLFW does not maximize correctly when maximizing a window with no decorations. Instead of taking up the working area when glfwMaximizeWindow() is called it takes up the entire screen (the function works fine for a decorated window). I don't know if that was the intended behavior or not, so I'm not calling it a bug, but the developer needs to be able to decide which behavior they want for undecorated windows as well.

There are other reasons why having the working area is necessary especially for things like floating windows for notifications or other widgets. Generally you want those to not cover the task bar, but you don't want them to be decorated.

@adambrown

This comment has been minimized.

Show comment
Hide comment
@adambrown

adambrown Dec 18, 2016

This is related to: #899 as 899 is the behavior that causes the first reason this functionality is needed. However, this functionality is necessary regardless of whether that bug is fixed or not so not closing this.

adambrown commented Dec 18, 2016

This is related to: #899 as 899 is the behavior that causes the first reason this functionality is needed. However, this functionality is necessary regardless of whether that bug is fixed or not so not closing this.

@elmindreda

This comment has been minimized.

Show comment
Hide comment
@elmindreda

elmindreda Dec 18, 2016

Member

Fair enough. I won't be adding this to 3.3 but it may be included in 3.4. A work area query could be useful.

Member

elmindreda commented Dec 18, 2016

Fair enough. I won't be adding this to 3.3 but it may be included in 3.4. A work area query could be useful.

@elmindreda elmindreda changed the title from Provide a way to get the working area of a screen to Query for desktop work area Dec 18, 2016

@NkD

This comment has been minimized.

Show comment
Hide comment
@NkD

NkD Mar 16, 2017

I am using GLFW in Java (LWJGL).
In Java we can get "working area" by AWT: Toolkit.getDefaultToolkit().getScreenInsets(conf).
But this fault in case if you have more then one monitor.
This bug is reported many years ago and still exists :(
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6899304

In Java doesn't have way how create work-around.
We need to provide working area directly via GLFW.

Please this is urgent for me and maybe for other Java developers.

NkD commented Mar 16, 2017

I am using GLFW in Java (LWJGL).
In Java we can get "working area" by AWT: Toolkit.getDefaultToolkit().getScreenInsets(conf).
But this fault in case if you have more then one monitor.
This bug is reported many years ago and still exists :(
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6899304

In Java doesn't have way how create work-around.
We need to provide working area directly via GLFW.

Please this is urgent for me and maybe for other Java developers.

@elmindreda elmindreda added this to the 3.4 milestone Mar 27, 2017

@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 6, 2017

Contributor

I believe that on X11, the work are in question can be retrieved with the property _NET_WORKAREA. I can work on this if no one is working on it yet.

Contributor

felselva commented Apr 6, 2017

I believe that on X11, the work are in question can be retrieved with the property _NET_WORKAREA. I can work on this if no one is working on it yet.

@elmindreda

This comment has been minimized.

Show comment
Hide comment
@elmindreda

elmindreda Apr 6, 2017

Member

@felipefs Please do! I had in mind an interface something like

void GLFWAPI glfwGetMonitorWorkarea(GLFWmonitor* monitor,
                                    int* xpos, int* ypos,
                                    int* width, int* height);
Member

elmindreda commented Apr 6, 2017

@felipefs Please do! I had in mind an interface something like

void GLFWAPI glfwGetMonitorWorkarea(GLFWmonitor* monitor,
                                    int* xpos, int* ypos,
                                    int* width, int* height);
@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 6, 2017

Contributor

I will get my hands on it when I finish the drag operation for Wayland.

Contributor

felselva commented Apr 6, 2017

I will get my hands on it when I finish the drag operation for Wayland.

@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 6, 2017

Contributor

It works on X11!
Magic

I will try to make for Windows.

@elmindreda do you prefer a pull request when the implementation is done for all platforms or I can make the pull for each separately? (same question for #923).

Contributor

felselva commented Apr 6, 2017

It works on X11!
Magic

I will try to make for Windows.

@elmindreda do you prefer a pull request when the implementation is done for all platforms or I can make the pull for each separately? (same question for #923).

@elmindreda

This comment has been minimized.

Show comment
Hide comment
@elmindreda

elmindreda Apr 6, 2017

Member

@felipefs I'd prefer a single branch and PR per feature, but you can make a PR of it before implementing for all platforms if you prefer and then add new commits as needed.

Member

elmindreda commented Apr 6, 2017

@felipefs I'd prefer a single branch and PR per feature, but you can make a PR of it before implementing for all platforms if you prefer and then add new commits as needed.

@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 6, 2017

Contributor

X11 implementation is on my branch: https://github.com/felipefs/glfw/tree/workarea

It seems the only way to retrieve the work area of a monitor on Windows is by using the handle HMONITOR and the function GetMonitorInfo. So far, the only way I know to get HMONITOR is by making a callback and pushing it to EnumDisplayMonitors, but it would still require a way to match the HMONITOR with the specified _GLFWmonitor (which I don't know how to do in this case).

Here is what I have so far (updated):

static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
    RECT *workarea = (RECT *)dwData; /* How to correctly grab this pointer? */
    MONITORINFO monitorInfo;
    GetMonitorInfo(hMonitor, &monitorInfo); / * Are we sure that this hMonitor is correspondent to our _GLFWmonitor? */
    workarea->left = monitorInfo.rcWork.left;
    workarea->top = monitorInfo.rcWork.top;
    workarea->right = monitorInfo.rcWork.right;
    workarea->bottom = monitorInfo.rcWork.bottom;
    return TRUE;
}

void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height)
{
    HDC dc;
    RECT workarea;

    dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);

    if (!EnumDisplayMonitors(dc, NULL, MonitorEnumProc, (LPARAM)&workarea)) /* We pass the workarea rect as pointer */
        return;

    DeleteDC(dc);

    *xpos = workarea.left;
    *ypos = workarea.top;
    *width = workarea.right;
    *height = workarea.bottom;
}

I suppose I need to make data a type that will hold the sent _GLFWmonitor and hold the returned HMONITOR. Anyone knows a better way than using this ugly callback?

@felipefs I'd prefer a single branch and PR per feature, but you can make a PR of it before implementing for all platforms if you prefer and then add new commits as needed.

Ok!

Contributor

felselva commented Apr 6, 2017

X11 implementation is on my branch: https://github.com/felipefs/glfw/tree/workarea

It seems the only way to retrieve the work area of a monitor on Windows is by using the handle HMONITOR and the function GetMonitorInfo. So far, the only way I know to get HMONITOR is by making a callback and pushing it to EnumDisplayMonitors, but it would still require a way to match the HMONITOR with the specified _GLFWmonitor (which I don't know how to do in this case).

Here is what I have so far (updated):

static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
    RECT *workarea = (RECT *)dwData; /* How to correctly grab this pointer? */
    MONITORINFO monitorInfo;
    GetMonitorInfo(hMonitor, &monitorInfo); / * Are we sure that this hMonitor is correspondent to our _GLFWmonitor? */
    workarea->left = monitorInfo.rcWork.left;
    workarea->top = monitorInfo.rcWork.top;
    workarea->right = monitorInfo.rcWork.right;
    workarea->bottom = monitorInfo.rcWork.bottom;
    return TRUE;
}

void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height)
{
    HDC dc;
    RECT workarea;

    dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);

    if (!EnumDisplayMonitors(dc, NULL, MonitorEnumProc, (LPARAM)&workarea)) /* We pass the workarea rect as pointer */
        return;

    DeleteDC(dc);

    *xpos = workarea.left;
    *ypos = workarea.top;
    *width = workarea.right;
    *height = workarea.bottom;
}

I suppose I need to make data a type that will hold the sent _GLFWmonitor and hold the returned HMONITOR. Anyone knows a better way than using this ugly callback?

@felipefs I'd prefer a single branch and PR per feature, but you can make a PR of it before implementing for all platforms if you prefer and then add new commits as needed.

Ok!

@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 7, 2017

Contributor

Aaand I got it working. Kinda. I need someone to test the Windows implementation on multiple monitors (as I don't have multiple monitors :P).

Here's my branch for test: https://github.com/felipefs/glfw/tree/workarea

I tested the Windows implementation on my Linux using Wine, and it worked fine. The example simple.c should print the work area on console (sorry for polluting simple.c, @elmindreda 😁)

As for the Wayland implementation: it seems that Wayland doesn't have the concept of work area. Maybe just return the monitor geometry, then?

Contributor

felselva commented Apr 7, 2017

Aaand I got it working. Kinda. I need someone to test the Windows implementation on multiple monitors (as I don't have multiple monitors :P).

Here's my branch for test: https://github.com/felipefs/glfw/tree/workarea

I tested the Windows implementation on my Linux using Wine, and it worked fine. The example simple.c should print the work area on console (sorry for polluting simple.c, @elmindreda 😁)

As for the Wayland implementation: it seems that Wayland doesn't have the concept of work area. Maybe just return the monitor geometry, then?

@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 7, 2017

Contributor

I'm gathering information about how to make the macOS implementation, but I will need help, as I'm not a Objective-C programmer.

There is two approaches related with screen space that I found, but I'm not sure that any of them have the concept of "work area":

  1. NSScreen visible​Frame, but we need to retrieve the NSScreen, probably done with CGDirectDisplayID, which we already have (I believe this is the correct one, according to the NSScreen documentation).
  2. CGRect CGDisplayBounds(CGDirectDisplayID id) which is easier than the option above.

What I know about them is that they retrieve values in different formats (one is relative to the main monitor, so might return negative values, the other is absolute).

Here's a sketch of the 2nd approach:

void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height)
{
    const CGRect bounds = CGDisplayBounds(monitor->ns.displayID);
    /* Get the values from CGRect */
}
Contributor

felselva commented Apr 7, 2017

I'm gathering information about how to make the macOS implementation, but I will need help, as I'm not a Objective-C programmer.

There is two approaches related with screen space that I found, but I'm not sure that any of them have the concept of "work area":

  1. NSScreen visible​Frame, but we need to retrieve the NSScreen, probably done with CGDirectDisplayID, which we already have (I believe this is the correct one, according to the NSScreen documentation).
  2. CGRect CGDisplayBounds(CGDirectDisplayID id) which is easier than the option above.

What I know about them is that they retrieve values in different formats (one is relative to the main monitor, so might return negative values, the other is absolute).

Here's a sketch of the 2nd approach:

void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height)
{
    const CGRect bounds = CGDisplayBounds(monitor->ns.displayID);
    /* Get the values from CGRect */
}
@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 7, 2017

Contributor

After some research, I have some code, but I need someone to review (I'm' not a Objective-C programmer):

void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height)
{
    NSScreen *resultScreen;
    for (NSScreen *screen in [NSScreen screens]) {
        if ([[[screen deviceDescription] valueForKey:@"NSScreenNumber"] intValue] == monitor->ns.displayID) {
            resultScreen = screen;
            break;
        }
    }

    NSRect frameRect = [[NSScreen resultScreen] visibleFrame];

    *xpos = NSMinX(frameRect);
    *ypos = NSMinY(frameRect);
    *width = NSMaxX(frameRect);
    *height = NSMaxY(frameRect);
}

Those NSMaxX and NSMaxY probably mean "right" and "bottom", instead of "width" and "height", but we can test first.

Contributor

felselva commented Apr 7, 2017

After some research, I have some code, but I need someone to review (I'm' not a Objective-C programmer):

void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height)
{
    NSScreen *resultScreen;
    for (NSScreen *screen in [NSScreen screens]) {
        if ([[[screen deviceDescription] valueForKey:@"NSScreenNumber"] intValue] == monitor->ns.displayID) {
            resultScreen = screen;
            break;
        }
    }

    NSRect frameRect = [[NSScreen resultScreen] visibleFrame];

    *xpos = NSMinX(frameRect);
    *ypos = NSMinY(frameRect);
    *width = NSMaxX(frameRect);
    *height = NSMaxY(frameRect);
}

Those NSMaxX and NSMaxY probably mean "right" and "bottom", instead of "width" and "height", but we can test first.

@felselva

This comment has been minimized.

Show comment
Hide comment
@felselva

felselva Apr 7, 2017

Contributor

Wayland and Mir implementation

I was reading this blog post of the Gtk development team, and found this:

On Mir, a MirSurfaceSpec is created, while on Wayland an xdg_positioner object is created. On X11, Windows and Mac OS X, the backends can use the available global positions as well as monitor work areas and calculate an optimal position just as before.

There is already a basic proof-of-concept in the Mir backend, and a Wayland implementation is in progress.

It seems that Wayland still doesn't provide a way to check for the work area, and currently the job is done using the XDG extension (but do we want to add that dependency when there's already work in progress for that?). As for Mir, there's only the proof of concept, but nothing on the documentation that I could find. Also there's the cloudy future of Mir.

Contributor

felselva commented Apr 7, 2017

Wayland and Mir implementation

I was reading this blog post of the Gtk development team, and found this:

On Mir, a MirSurfaceSpec is created, while on Wayland an xdg_positioner object is created. On X11, Windows and Mac OS X, the backends can use the available global positions as well as monitor work areas and calculate an optimal position just as before.

There is already a basic proof-of-concept in the Mir backend, and a Wayland implementation is in progress.

It seems that Wayland still doesn't provide a way to check for the work area, and currently the job is done using the XDG extension (but do we want to add that dependency when there's already work in progress for that?). As for Mir, there's only the proof of concept, but nothing on the documentation that I could find. Also there's the cloudy future of Mir.

@TheStormN

This comment has been minimized.

Show comment
Hide comment
@TheStormN

TheStormN Oct 15, 2017

You can use Code from the Qt Framework. They have very nice class QScreen with have a method named availableGeometry() which does exactly what you are looking for. :)
http://doc.qt.io/qt-5/qscreen.html#availableGeometry-prop

TheStormN commented Oct 15, 2017

You can use Code from the Qt Framework. They have very nice class QScreen with have a method named availableGeometry() which does exactly what you are looking for. :)
http://doc.qt.io/qt-5/qscreen.html#availableGeometry-prop

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment