diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 5436b9b48..292c91db9 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -900,6 +900,15 @@ extern "C" { #define GLFW_EGL_CONTEXT_API 0x00036002 #define GLFW_OSMESA_CONTEXT_API 0x00036003 +#define GLFW_WINDOW_LEFT 0 +#define GLFW_WINDOW_TOP 1 +#define GLFW_WINDOW_RIGHT 2 +#define GLFW_WINDOW_BOTTOM 3 +#define GLFW_WINDOW_TOPLEFT 4 +#define GLFW_WINDOW_TOPRIGHT 5 +#define GLFW_WINDOW_BOTTOMLEFT 6 +#define GLFW_WINDOW_BOTTOMRIGHT 7 + /*! @defgroup shapes Standard cursor shapes * @brief Standard system cursor shapes. * @@ -2751,6 +2760,36 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window); */ GLFWAPI void glfwFocusWindow(GLFWwindow* window); +/*! @brief Starts a resize operation with the specified window. + * + * This function starts a resize operation on one of the borders of the + * specified window. + * + * The borders are [GLFW_WINDOW_LEFT](@ref GLFW_GLFW_WINDOW_LEFT), + * [GLFW_WINDOW_TOP](@ref GLFW_WINDOW_TOP), + * [GLFW_WINDOW_RIGHT](@ref GLFW_WINDOW_RIGHT), + * [GLFW_WINDOW_BOTTOM](@ref GLFW_WINDOW_BOTTOM), + * [GLFW_WINDOW_TOPLEFT](@ref GLFW_WINDOW_TOPLEFT), + * [GLFW_WINDOW_TOPRIGHT](@ref GLFW_WINDOW_TOPRIGHT), + * [GLFW_WINDOW_BOTTOMLEFT](@ref GLFW_WINDOW_BOTTOMLEFT) and + * [GLFW_WINDOW_BOTTOMRIGHT](@ref GLFW_WINDOW_BOTTOMRIGHT). + * + * @param[in] window The window to start the resize operation. + * @param[in] border One of the window borders. + * + * @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 window_resize + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI void glfwResizeWindow(GLFWwindow* window, int border); + /*! @brief Returns the monitor that the window uses for full screen mode. * * This function returns the handle of the monitor that the specified window is diff --git a/src/internal.h b/src/internal.h index be9ced898..72314cb1b 100644 --- a/src/internal.h +++ b/src/internal.h @@ -631,6 +631,7 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window); void _glfwPlatformShowWindow(_GLFWwindow* window); void _glfwPlatformHideWindow(_GLFWwindow* window); void _glfwPlatformFocusWindow(_GLFWwindow* window); +void _glfwPlatformResizeWindow(_GLFWwindow* window, int border); void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); int _glfwPlatformWindowFocused(_GLFWwindow* window); int _glfwPlatformWindowIconified(_GLFWwindow* window); diff --git a/src/window.c b/src/window.c index bf98723ea..36d6d6b84 100644 --- a/src/window.c +++ b/src/window.c @@ -698,6 +698,19 @@ GLFWAPI void glfwFocusWindow(GLFWwindow* handle) _glfwPlatformFocusWindow(window); } +GLFWAPI void glfwResizeWindow(GLFWwindow* handle, int border) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + if (border < GLFW_WINDOW_LEFT || border > GLFW_WINDOW_BOTTOMRIGHT) + return; + + _glfwPlatformResizeWindow(window, border); +} + GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/x11_window.c b/src/x11_window.c index e1c2a3e3e..d7e852fa8 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -43,6 +43,15 @@ #define _NET_WM_STATE_REMOVE 0 #define _NET_WM_STATE_ADD 1 #define _NET_WM_STATE_TOGGLE 2 +#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 +#define _NET_WM_MOVERESIZE_SIZE_TOP 1 +#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 +#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 +#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 + // Additional mouse button names for XButtonEvent #define Button6 6 @@ -2091,6 +2100,53 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) XFlush(_glfw.x11.display); } +void _glfwPlatformResizeWindow(_GLFWwindow* window, int border) +{ + int winXpos, winYpos; + double curXpos, curYpos; + XClientMessageEvent xclient; + memset(&xclient, 0, sizeof(XClientMessageEvent)); + XUngrabPointer(_glfw.x11.display, 0); + XFlush(_glfw.x11.display); + _glfwPlatformGetCursorPos(window, &curXpos, &curYpos); + _glfwPlatformGetWindowPos(window, &winXpos, &winYpos); + xclient.type = ClientMessage; + xclient.window = window->x11.handle; + xclient.message_type = XInternAtom(_glfw.x11.display, "_NET_WM_MOVERESIZE", False); + xclient.format = 32; + xclient.data.l[0] = winXpos + curXpos; + xclient.data.l[1] = winYpos + curYpos; + switch (border) + { + case GLFW_WINDOW_LEFT: + xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_LEFT; + break; + case GLFW_WINDOW_TOP: + xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_TOP; + break; + case GLFW_WINDOW_RIGHT: + xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_RIGHT; + break; + case GLFW_WINDOW_BOTTOM: + xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_BOTTOM; + break; + case GLFW_WINDOW_TOPLEFT: + xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_TOPLEFT; + break; + case GLFW_WINDOW_TOPRIGHT: + xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT; + break; + case GLFW_WINDOW_BOTTOMLEFT: + xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT; + break; + case GLFW_WINDOW_BOTTOMRIGHT: + xclient.data.l[2] = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT; + } + xclient.data.l[3] = 0; + xclient.data.l[4] = 0; + XSendEvent(_glfw.x11.display, _glfw.x11.root, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xclient); +} + void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos,