diff --git a/README.md b/README.md index 452577de..64b34ddf 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,7 @@ information on what to include when reporting a bug. ## Changelog + - Added `glfwDragWindow` function for starting a drag operation on a window - Added `GLFW_PLATFORM` init hint for runtime platform selection (#1958) - Added `GLFW_ANY_PLATFORM`, `GLFW_PLATFORM_WIN32`, `GLFW_PLATFORM_COCOA`, `GLFW_PLATFORM_WAYLAND`, `GLFW_PLATFORM_X11` and `GLFW_PLATFORM_NULL` symbols to diff --git a/examples/windows.c b/examples/windows.c index 598e5218..07b05b28 100644 --- a/examples/windows.c +++ b/examples/windows.c @@ -31,6 +31,12 @@ #include #include +void mouse_button_callback(GLFWwindow* window, int button, int action, int mods){ + if(button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS){ + glfwDragWindow(window); + } +} + int main(int argc, char** argv) { int xpos, ypos, height; @@ -79,6 +85,7 @@ int main(int argc, char** argv) xpos + size * (1 + (i & 1)), ypos + size * (1 + (i >> 1))); glfwSetInputMode(windows[i], GLFW_STICKY_KEYS, GLFW_TRUE); + glfwSetMouseButtonCallback(windows[i], mouse_button_callback); glfwMakeContextCurrent(windows[i]); gladLoadGL(glfwGetProcAddress); diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index aa6ddc33..2d6a58cf 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -3842,6 +3842,23 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window); */ GLFWAPI void glfwFocusWindow(GLFWwindow* window); +/*! @brief Starts drag operation to the specified window. + * + * This function starts the drag operation of the specified window. + * + * @param[in] window The window to start the dragging operation. + * + * @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. + * + * @since Added in version 3.4. + * + * @ingroup window + */ +GLFWAPI void glfwDragWindow(GLFWwindow* handle); + /*! @brief Requests user attention to the specified window. * * This function requests user attention to the specified window. On diff --git a/src/cocoa_init.m b/src/cocoa_init.m index aa369f9c..97060342 100644 --- a/src/cocoa_init.m +++ b/src/cocoa_init.m @@ -541,6 +541,7 @@ GLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform) _glfwHideWindowCocoa, _glfwRequestWindowAttentionCocoa, _glfwFocusWindowCocoa, + _glfwDragWindowCocoa, _glfwSetWindowMonitorCocoa, _glfwWindowFocusedCocoa, _glfwWindowIconifiedCocoa, diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 9f7d191d..320a96ca 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -234,6 +234,7 @@ void _glfwShowWindowCocoa(_GLFWwindow* window); void _glfwHideWindowCocoa(_GLFWwindow* window); void _glfwRequestWindowAttentionCocoa(_GLFWwindow* window); void _glfwFocusWindowCocoa(_GLFWwindow* window); +void _glfwDragWindowCocoa(_GLFWwindow* window); void _glfwSetWindowMonitorCocoa(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); GLFWbool _glfwWindowFocusedCocoa(_GLFWwindow* window); GLFWbool _glfwWindowIconifiedCocoa(_GLFWwindow* window); diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 5bb1289b..af64aa86 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1218,6 +1218,11 @@ void _glfwFocusWindowCocoa(_GLFWwindow* window) } // autoreleasepool } +void _glfwDragWindowCocoa(_GLFWwindow* window) +{ + // TODO +} + void _glfwSetWindowMonitorCocoa(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, diff --git a/src/internal.h b/src/internal.h index 89a18628..c3bf7efe 100644 --- a/src/internal.h +++ b/src/internal.h @@ -724,6 +724,7 @@ struct _GLFWplatform void (*hideWindow)(_GLFWwindow*); void (*requestWindowAttention)(_GLFWwindow*); void (*focusWindow)(_GLFWwindow*); + void (*dragWindow)(_GLFWwindow*); void (*setWindowMonitor)(_GLFWwindow*,_GLFWmonitor*,int,int,int,int,int); GLFWbool (*windowFocused)(_GLFWwindow*); GLFWbool (*windowIconified)(_GLFWwindow*); diff --git a/src/null_init.c b/src/null_init.c index de4b28f3..c1341eb3 100644 --- a/src/null_init.c +++ b/src/null_init.c @@ -89,6 +89,7 @@ GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform) _glfwHideWindowNull, _glfwRequestWindowAttentionNull, _glfwFocusWindowNull, + _glfwDragWindowNull, _glfwSetWindowMonitorNull, _glfwWindowFocusedNull, _glfwWindowIconifiedNull, diff --git a/src/null_platform.h b/src/null_platform.h index b646acb3..690d9d84 100644 --- a/src/null_platform.h +++ b/src/null_platform.h @@ -118,6 +118,7 @@ void _glfwRequestWindowAttentionNull(_GLFWwindow* window); void _glfwRequestWindowAttentionNull(_GLFWwindow* window); void _glfwHideWindowNull(_GLFWwindow* window); void _glfwFocusWindowNull(_GLFWwindow* window); +void _glfwDragWindowNull(_GLFWwindow* window); GLFWbool _glfwWindowFocusedNull(_GLFWwindow* window); GLFWbool _glfwWindowIconifiedNull(_GLFWwindow* window); GLFWbool _glfwWindowVisibleNull(_GLFWwindow* window); diff --git a/src/null_window.c b/src/null_window.c index 8a7cae41..ee95c597 100644 --- a/src/null_window.c +++ b/src/null_window.c @@ -461,6 +461,11 @@ void _glfwFocusWindowNull(_GLFWwindow* window) _glfwInputWindowFocus(window, GLFW_TRUE); } +void _glfwDragWindowNull(_GLFWwindow* window) +{ + // TODO +} + GLFWbool _glfwWindowFocusedNull(_GLFWwindow* window) { return _glfw.null.focusedWindow == window; diff --git a/src/win32_init.c b/src/win32_init.c index 8704150c..1c719a6f 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -652,6 +652,7 @@ GLFWbool _glfwConnectWin32(int platformID, _GLFWplatform* platform) _glfwHideWindowWin32, _glfwRequestWindowAttentionWin32, _glfwFocusWindowWin32, + _glfwDragWindowWin32, _glfwSetWindowMonitorWin32, _glfwWindowFocusedWin32, _glfwWindowIconifiedWin32, diff --git a/src/win32_platform.h b/src/win32_platform.h index c2158943..27fc8c67 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -557,6 +557,7 @@ void _glfwShowWindowWin32(_GLFWwindow* window); void _glfwHideWindowWin32(_GLFWwindow* window); void _glfwRequestWindowAttentionWin32(_GLFWwindow* window); void _glfwFocusWindowWin32(_GLFWwindow* window); +void _glfwDragWindowWin32(_GLFWwindow* window); void _glfwSetWindowMonitorWin32(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); GLFWbool _glfwWindowFocusedWin32(_GLFWwindow* window); GLFWbool _glfwWindowIconifiedWin32(_GLFWwindow* window); diff --git a/src/win32_window.c b/src/win32_window.c index 168529e2..03c06e52 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1751,6 +1751,12 @@ void _glfwFocusWindowWin32(_GLFWwindow* window) SetFocus(window->win32.handle); } +void _glfwDragWindowWin32(_GLFWwindow* window) +{ + ReleaseCapture(); + SendMessage(window->win32.handle, WM_NCLBUTTONDOWN, HTCAPTION, 0); +} + void _glfwSetWindowMonitorWin32(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, diff --git a/src/window.c b/src/window.c index ebbc6dca..64ef378a 100644 --- a/src/window.c +++ b/src/window.c @@ -833,6 +833,16 @@ GLFWAPI void glfwFocusWindow(GLFWwindow* handle) _glfw.platform.focusWindow(window); } +GLFWAPI void glfwDragWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + _glfw.platform.dragWindow(window); +} + GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/wl_init.c b/src/wl_init.c index 2ce6f7f9..5822cf39 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -401,6 +401,7 @@ GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform) _glfwHideWindowWayland, _glfwRequestWindowAttentionWayland, _glfwFocusWindowWayland, + _glfwDragWindowWayland, _glfwSetWindowMonitorWayland, _glfwWindowFocusedWayland, _glfwWindowIconifiedWayland, diff --git a/src/wl_platform.h b/src/wl_platform.h index b85d79a5..0da06d8d 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -462,6 +462,7 @@ void _glfwShowWindowWayland(_GLFWwindow* window); void _glfwHideWindowWayland(_GLFWwindow* window); void _glfwRequestWindowAttentionWayland(_GLFWwindow* window); void _glfwFocusWindowWayland(_GLFWwindow* window); +void _glfwDragWindowWayland(_GLFWwindow* window); void _glfwSetWindowMonitorWayland(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); GLFWbool _glfwWindowFocusedWayland(_GLFWwindow* window); GLFWbool _glfwWindowIconifiedWayland(_GLFWwindow* window); diff --git a/src/wl_window.c b/src/wl_window.c index 1661d241..b8421545 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -2087,6 +2087,11 @@ void _glfwFocusWindowWayland(_GLFWwindow* window) "Wayland: The platform does not support setting the input focus"); } +void _glfwDragWindowWayland(_GLFWwindow* window) +{ + wl_shell_surface_move(window->wl.shellSurface, _glfw.wl.seat, _glfw.wl.pointerSerial); +} + void _glfwSetWindowMonitorWayland(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, diff --git a/src/x11_init.c b/src/x11_init.c index 11aeb9e5..710bd041 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -1223,6 +1223,7 @@ GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform) _glfwHideWindowX11, _glfwRequestWindowAttentionX11, _glfwFocusWindowX11, + _glfwDragWindowX11, _glfwSetWindowMonitorX11, _glfwWindowFocusedX11, _glfwWindowIconifiedX11, diff --git a/src/x11_platform.h b/src/x11_platform.h index ecaa0fa4..73383714 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -922,6 +922,7 @@ void _glfwShowWindowX11(_GLFWwindow* window); void _glfwHideWindowX11(_GLFWwindow* window); void _glfwRequestWindowAttentionX11(_GLFWwindow* window); void _glfwFocusWindowX11(_GLFWwindow* window); +void _glfwDragWindowX11(_GLFWwindow* window); void _glfwSetWindowMonitorX11(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); GLFWbool _glfwWindowFocusedX11(_GLFWwindow* window); GLFWbool _glfwWindowIconifiedX11(_GLFWwindow* window); diff --git a/src/x11_window.c b/src/x11_window.c index 98f990b2..092066e3 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -45,6 +45,7 @@ #define _NET_WM_STATE_REMOVE 0 #define _NET_WM_STATE_ADD 1 #define _NET_WM_STATE_TOGGLE 2 +#define _NET_WM_MOVERESIZE_MOVE 8 // Additional mouse button names for XButtonEvent #define Button6 6 @@ -2405,6 +2406,28 @@ void _glfwFocusWindowX11(_GLFWwindow* window) XFlush(_glfw.x11.display); } +void _glfwDragWindowX11(_GLFWwindow* window) +{ + int winXpos, winYpos; + double curXpos, curYpos; + XClientMessageEvent xclient; + memset(&xclient, 0, sizeof(XClientMessageEvent)); + XUngrabPointer(_glfw.x11.display, 0); + XFlush(_glfw.x11.display); + _glfwGetCursorPosX11(window, &curXpos, &curYpos); + _glfwGetWindowPosX11(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; + xclient.data.l[2] = _NET_WM_MOVERESIZE_MOVE; + xclient.data.l[3] = 0; + xclient.data.l[4] = 0; + XSendEvent(_glfw.x11.display, _glfw.x11.root, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xclient); +} + void _glfwSetWindowMonitorX11(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos,