diff --git a/README.md b/README.md index c1375252..0ce4db50 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,8 @@ The following dependencies are needed by the examples and test programs: - Added `glfwPostEmptyEvent` for allowing secondary threads to cause `glfwWaitEvents` to return - Added `empty` test program for verifying posting of empty events + - Added `glfwGetWindowFrameSize` for retrieving the size of the frame around + the client area of a window - Added `GLFW_INCLUDE_ES31` for including the OpenGL ES 3.1 header - Bugfix: The debug context attribute was set from `GL_ARB_debug_output` even when a debug context had not been requested diff --git a/docs/news.dox b/docs/news.dox index 94ecf9ef..c0530fb0 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -27,6 +27,12 @@ event from a secondary thread to the main thread event queue, causing @ref glfwWaitEvents to return. +@subsection news_31_framesize Window frame size query + +GLFW now supports querying the size, on each side, of the frame around the +client area of a window, with @ref glfwGetWindowFrameSize. + + @section news_30 New features in version 3.0 @subsection news_30_cmake CMake build system diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 43614174..53f518a1 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1498,6 +1498,33 @@ GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height); */ GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height); +/*! @brief Retrieves the size of the frame of the window. + * + * This function retrieves the size, in screen coordinates, of each edge of the + * frame of the specified window. This size includes the title bar, if the + * window has one. The size of the frame may vary depending on the + * [window-related hints](@ref window_hints_wnd) used to create it. + * + * @param[in] window The window whose frame size to query. + * @param[out] left Where to store the size, in screen coordinates, of the left + * edge of the window frame. + * @param[out] top Where to store the offset, in screen coordinates, of the top + * edge of the window frame. + * @param[out] right Where to store the offset, in screen coordinates, of the + * right edge of the window frame. + * @param[out] bottom Where to store the offset, in screen coordinates, of the + * bottom edge of the window frame. + * + * @remarks This function returns the size of each window frame edge, not its + * offset from the client area edge, so the returned values will always be zero + * or positive. + * + * @note This function may only be called from the main thread. + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int* right, int* bottom); + /*! @brief Iconifies the specified window. * * This function iconifies/minimizes the specified window, if it was previously diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 35b0c9c8..cbf74ecd 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1091,6 +1091,25 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* heigh *height = (int) fbRect.size.height; } +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + const NSRect contentRect = [window->ns.view frame]; + const NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect]; + + if (left) + *left = contentRect.origin.x - frameRect.origin.x; + if (top) + *top = frameRect.origin.y + frameRect.size.height - + contentRect.origin.y - contentRect.size.height; + if (right) + *right = frameRect.origin.x + frameRect.size.width - + contentRect.origin.x - contentRect.size.width; + if (bottom) + *bottom = contentRect.origin.y - frameRect.origin.y; +} + void _glfwPlatformIconifyWindow(_GLFWwindow* window) { if (window->monitor) diff --git a/src/internal.h b/src/internal.h index d3e0471c..7a44d12f 100644 --- a/src/internal.h +++ b/src/internal.h @@ -524,6 +524,11 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height); */ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height); +/*! @copydoc glfwGetWindowFrameSize + * @ingroup platform + */ +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom); + /*! @copydoc glfwIconifyWindow * @ingroup platform */ diff --git a/src/win32_window.c b/src/win32_window.c index 7de8df11..2b04ac71 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1120,6 +1120,28 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* heigh _glfwPlatformGetWindowSize(window, width, height); } +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + RECT rect; + int width, height; + + _glfwPlatformGetWindowSize(window, &width, &height); + SetRect(&rect, 0, 0, width, height); + AdjustWindowRectEx(&rect, window->win32.dwStyle, + FALSE, window->win32.dwExStyle); + + if (left) + *left = -rect.left; + if (top) + *top = -rect.top; + if (right) + *right = rect.right - width; + if (bottom) + *bottom = rect.bottom - height; +} + void _glfwPlatformIconifyWindow(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_MINIMIZE); diff --git a/src/window.c b/src/window.c index 0c7eb014..e9e575e6 100644 --- a/src/window.c +++ b/src/window.c @@ -488,6 +488,15 @@ GLFWAPI void glfwGetFramebufferSize(GLFWwindow* handle, int* width, int* height) _glfwPlatformGetFramebufferSize(window, width, height); } +GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* handle, + int* left, int* top, + int* right, int* bottom) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetWindowFrameSize(window, left, top, right, bottom); +} + GLFWAPI void glfwIconifyWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/x11_init.c b/src/x11_init.c index 4dc46d48..393eb277 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -415,6 +415,8 @@ static void detectEWMH(void) getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_PING"); _glfw.x11.NET_ACTIVE_WINDOW = getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW"); + _glfw.x11.NET_FRAME_EXTENTS = + getSupportedAtom(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS"); _glfw.x11.NET_WM_BYPASS_COMPOSITOR = getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_BYPASS_COMPOSITOR"); diff --git a/src/x11_platform.h b/src/x11_platform.h index b76a1393..dad69aef 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -120,6 +120,7 @@ typedef struct _GLFWlibraryX11 Atom NET_WM_STATE_FULLSCREEN; Atom NET_WM_BYPASS_COMPOSITOR; Atom NET_ACTIVE_WINDOW; + Atom NET_FRAME_EXTENTS; Atom MOTIF_WM_HINTS; // Xdnd (drag and drop) atoms diff --git a/src/x11_window.c b/src/x11_window.c index b92cdfcc..b744c89d 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1234,6 +1234,43 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* heigh _glfwPlatformGetWindowSize(window, width, height); } +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + long* extents = NULL; + + if (left) + *left = 0; + if (top) + *top = 0; + if (right) + *right = 0; + if (bottom) + *bottom = 0; + + if (_glfw.x11.NET_FRAME_EXTENTS == None) + return; + + if (_glfwGetWindowProperty(window->x11.handle, + _glfw.x11.NET_FRAME_EXTENTS, + XA_CARDINAL, + (unsigned char**) &extents) == 4) + { + if (left) + *left = extents[0]; + if (top) + *top = extents[2]; + if (right) + *right = extents[1]; + if (bottom) + *bottom = extents[3]; + } + + if (extents) + XFree(extents); +} + void _glfwPlatformIconifyWindow(_GLFWwindow* window) { if (window->x11.overrideRedirect)