diff --git a/README.md b/README.md index 155e5ae50..077c86daf 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,7 @@ information on what to include when reporting a bug. ## Changelog +- Added `glfwDragWindow` function for starting a drag operation on a window - 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 7752a3655..692fa5b35 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -68,6 +68,12 @@ static void error_callback(int error, const char* description) fprintf(stderr, "Error: %s\n", description); } +void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) +{ + if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) + glfwDragWindow(window); +} + static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) @@ -96,6 +102,7 @@ int main(void) } glfwSetKeyCallback(window, key_callback); + glfwSetMouseButtonCallback(window, mouse_button_callback); glfwMakeContextCurrent(window); gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 5436b9b48..0c0bc4147 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -2751,6 +2751,25 @@ 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. + * + * @sa @ref window_drag + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwDragWindow(GLFWwindow* handle); + /*! @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/cocoa_window.m b/src/cocoa_window.m index d2aab85f9..e606bcb2d 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1288,6 +1288,10 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) [window->ns.object makeKeyAndOrderFront:nil]; } +void _glfwPlatformDragWindow(_GLFWwindow* window) +{ +} + void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, diff --git a/src/internal.h b/src/internal.h index be9ced898..3a52d2b02 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 _glfwPlatformDragWindow(_GLFWwindow* window); 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/mir_window.c b/src/mir_window.c index e380f4070..484690be6 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -576,6 +576,10 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) "Mir: Unsupported function %s", __PRETTY_FUNCTION__); } +void _glfwPlatformDragWindow(_GLFWwindow* window) +{ +} + void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, diff --git a/src/null_window.c b/src/null_window.c index 7f0101d44..3ca26f292 100644 --- a/src/null_window.c +++ b/src/null_window.c @@ -184,6 +184,10 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) { } +void _glfwPlatformDragWindow(_GLFWwindow* window) +{ +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { return GLFW_FALSE; diff --git a/src/win32_window.c b/src/win32_window.c index 363ef0f32..487376979 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1323,6 +1323,12 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) SetFocus(window->win32.handle); } +void _glfwPlatformDragWindow(_GLFWwindow* window) +{ + ReleaseCapture(); + SendMessage(window->win32.handle, WM_NCLBUTTONDOWN, HTCAPTION, 0); +} + void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, diff --git a/src/window.c b/src/window.c index bf98723ea..622d4908c 100644 --- a/src/window.c +++ b/src/window.c @@ -698,6 +698,16 @@ GLFWAPI void glfwFocusWindow(GLFWwindow* handle) _glfwPlatformFocusWindow(window); } +GLFWAPI void glfwDragWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + + _glfwPlatformDragWindow(window); +} + GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/wl_window.c b/src/wl_window.c index e6c554527..442f57d8f 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -605,6 +605,11 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) "Wayland: Focusing a window requires user interaction"); } +void _glfwPlatformDragWindow(_GLFWwindow* window) +{ + wl_shell_surface_move(window->wl.shellSurface, _glfw.wl.seat, _glfw.wl.pointerSerial); +} + void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, diff --git a/src/x11_window.c b/src/x11_window.c index e1c2a3e3e..f83f44d57 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -43,6 +43,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 @@ -2091,6 +2092,28 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) XFlush(_glfw.x11.display); } +void _glfwPlatformDragWindow(_GLFWwindow* window) +{ + 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; + 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 _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos,