Add glfwGetMonitorWorkarea

This function retrieves the work area rectangle of the specified
monitor.

Related to #920.
Closes #989.
diff --git a/README.md b/README.md
index 382b5b5..af7a3b1 100644
--- a/README.md
+++ b/README.md
@@ -141,6 +141,7 @@
   (#235,#439,#677,#845,#898)
 - Added `glfwRequestWindowAttention` function for requesting attention from the
   user (#732,#988)
+- Added `glfwGetMonitorWorkarea` function for querying the monitor work area
 - Added `glfwGetKeyScancode` function that allows retrieving platform dependent
   scancodes for keys (#830)
 - Added `glfwSetWindowMaximizeCallback` and `GLFWwindowmaximizefun` for
diff --git a/examples/simple.c b/examples/simple.c
index 7752a36..ce9c22d 100644
--- a/examples/simple.c
+++ b/examples/simple.c
@@ -79,6 +79,7 @@
     GLFWwindow* window;
     GLuint vertex_buffer, vertex_shader, fragment_shader, program;
     GLint mvp_location, vpos_location, vcol_location;
+    int workarea_x, workarea_y, workarea_width, workarea_height;
 
     glfwSetErrorCallback(error_callback);
 
@@ -131,6 +132,8 @@
     glVertexAttribPointer(vcol_location, 3, GL_FLOAT, GL_FALSE,
                           sizeof(vertices[0]), (void*) (sizeof(float) * 2));
 
+    glfwGetMonitorWorkarea(glfwGetPrimaryMonitor(), &workarea_x, &workarea_y, &workarea_width, &workarea_height);
+    printf("Monitor work area: %d, %d, %d, %d\n", workarea_x, workarea_y, workarea_width, workarea_height);
     while (!glfwWindowShouldClose(window))
     {
         float ratio;
diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h
index 57d5c9c..3019b95 100644
--- a/include/GLFW/glfw3.h
+++ b/include/GLFW/glfw3.h
@@ -1931,6 +1931,31 @@
  */
 GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos);
 
+/*! @brief Returns the work area of the monitor.
+ *
+ *  This function returns the position, in screen coordinates, of the upper-left
+ *  corner of the specified monitor.
+ *
+ *  Any or all of the position arguments may be `NULL`.  If an error occurs, all
+ *  non-`NULL` position arguments will be set to zero.
+ *
+ *  @param[in] monitor The monitor to query.
+ *  @param[out] xpos Where to store the monitor x-coordinate, or `NULL`.
+ *  @param[out] ypos Where to store the monitor y-coordinate, or `NULL`.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
+ *  GLFW_PLATFORM_ERROR.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref monitor_properties
+ *
+ *  @since Added in version 3.0.
+ *
+ *  @ingroup monitor
+ */
+GLFWAPI void glfwGetMonitorWorkarea(GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height);
+
 /*! @brief Returns the physical size of the monitor.
  *
  *  This function returns the size, in millimetres, of the display area of the
diff --git a/src/cocoa_monitor.m b/src/cocoa_monitor.m
index 5767d24..736a905 100644
--- a/src/cocoa_monitor.m
+++ b/src/cocoa_monitor.m
@@ -408,6 +408,24 @@
         *yscale = (float) (pixels.size.height / points.size.height);
 }
 
+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);
+}
+
 GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
 {
     CFArrayRef modes;
diff --git a/src/internal.h b/src/internal.h
index abba5ba..3d5e22f 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -612,6 +612,7 @@
 void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos);
 void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
                                          float* xscale, float* yscale);
+void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height);
 GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count);
 void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode);
 GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
diff --git a/src/monitor.c b/src/monitor.c
index 0ab865e..869fdfb 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -330,6 +330,25 @@
     _glfwPlatformGetMonitorPos(monitor, xpos, ypos);
 }
 
+GLFWAPI void glfwGetMonitorWorkarea(GLFWmonitor* handle, int* xpos, int* ypos, int* width, int* height)
+{
+    _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
+    assert(monitor != NULL);
+
+    if (xpos)
+        *xpos = 0;
+    if (ypos)
+        *ypos = 0;
+    if (width)
+        *width = 0;
+    if (width)
+        *width = 0;
+
+    _GLFW_REQUIRE_INIT();
+
+    _glfwPlatformGetMonitorWorkarea(monitor, xpos, ypos, width, height);
+}
+
 GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM)
 {
     _GLFWmonitor* monitor = (_GLFWmonitor*) handle;
diff --git a/src/null_monitor.c b/src/null_monitor.c
index 45c4a10..9979737 100644
--- a/src/null_monitor.c
+++ b/src/null_monitor.c
@@ -49,6 +49,10 @@
         *yscale = 1.f;
 }
 
+void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height)
+{
+}
+
 GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
 {
     return NULL;
diff --git a/src/win32_monitor.c b/src/win32_monitor.c
index 07b3614..a8fb4fc 100644
--- a/src/win32_monitor.c
+++ b/src/win32_monitor.c
@@ -361,6 +361,37 @@
     _glfwGetMonitorContentScaleWin32(monitor->win32.handle, xscale, yscale);
 }
 
+static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
+{
+    RECT *workarea = (RECT *)dwData;
+    MONITORINFO monitorInfo;
+    monitorInfo.cbSize = sizeof(MONITORINFO);
+    GetMonitorInfo(hMonitor, &monitorInfo);
+    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))
+        return;
+
+    DeleteDC(dc);
+
+    *xpos = workarea.left;
+    *ypos = workarea.top;
+    *width = workarea.right;
+    *height = workarea.bottom;
+}
+
 GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
 {
     int modeIndex = 0, size = 0;
diff --git a/src/x11_init.c b/src/x11_init.c
index e3e3ad5..f1e7261 100644
--- a/src/x11_init.c
+++ b/src/x11_init.c
@@ -446,6 +446,8 @@
         getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE");
     _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL =
         getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL");
+    _glfw.x11.NET_WORKAREA =
+        getSupportedAtom(supportedAtoms, atomCount, "_NET_WORKAREA");
     _glfw.x11.NET_ACTIVE_WINDOW =
         getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW");
     _glfw.x11.NET_FRAME_EXTENTS =
diff --git a/src/x11_monitor.c b/src/x11_monitor.c
index 240e9fb..d0aa9f9 100644
--- a/src/x11_monitor.c
+++ b/src/x11_monitor.c
@@ -342,6 +342,22 @@
         *yscale = _glfw.x11.contentScaleY;
 }
 
+void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor, int* xpos, int* ypos, int *width, int *height)
+{
+    if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
+    {
+        Atom* extents = NULL;
+
+        _glfwGetWindowPropertyX11(_glfw.x11.root, _glfw.x11.NET_WORKAREA, XA_CARDINAL, (unsigned char**) &extents);
+
+        *xpos = extents[0];
+        *ypos = extents[1];
+        *width = extents[2];
+        *height = extents[3];
+        XFree(extents);
+    }
+}
+
 GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
 {
     GLFWvidmode* result;
diff --git a/src/x11_platform.h b/src/x11_platform.h
index c37c740..153daee 100644
--- a/src/x11_platform.h
+++ b/src/x11_platform.h
@@ -259,6 +259,7 @@
     Atom            NET_WM_FULLSCREEN_MONITORS;
     Atom            NET_WM_WINDOW_OPACITY;
     Atom            NET_WM_CM_Sx;
+    Atom            NET_WORKAREA;
     Atom            NET_ACTIVE_WINDOW;
     Atom            NET_FRAME_EXTENTS;
     Atom            NET_REQUEST_FRAME_EXTENTS;