From a4c76fbeed6c1a735b883c86c256e07d4958193b Mon Sep 17 00:00:00 2001 From: Felipe Ferreira da Silva Date: Wed, 5 Apr 2017 22:14:09 -0300 Subject: [PATCH] Add glfwDragWindow This is the initial implementation of glfwDragWindow, with support for X11. The function glfwDragWindow requires only the target window to be dragged. To make the function easier and more portable, the position of the window and of the cursor are grabbed internally, so the end-user do not need to pass them manually. The example 'simple.c' was updated to include this functionality when clicking on the client area of the window. --- README.md | 1 + examples/simple.c | 7 +++++++ include/GLFW/glfw3.h | 15 +++++++++++++++ src/cocoa_window.m | 4 ++++ src/internal.h | 1 + src/mir_window.c | 4 ++++ src/null_window.c | 4 ++++ src/win32_window.c | 6 ++++++ src/window.c | 10 ++++++++++ src/wl_window.c | 5 +++++ src/x11_window.c | 23 +++++++++++++++++++++++ 11 files changed, 80 insertions(+) diff --git a/README.md b/README.md index 3353dacc..841f610e 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ information on what to include when reporting a bug. for retrieving gamepad input state (#900) - Added `glfwRequestWindowAttention` function for requesting attention from the user (#732,#988) +- 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 7752a365..692fa5b3 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 25326252..1cd05759 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -2929,6 +2929,21 @@ 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. + * @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 Requests user attention to the specified window. * * This function requests user attention to the specified window. On diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 2acfa98b..c7f15ffc 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1298,6 +1298,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 fdff84d0..111e3a41 100644 --- a/src/internal.h +++ b/src/internal.h @@ -674,6 +674,7 @@ void _glfwPlatformShowWindow(_GLFWwindow* window); void _glfwPlatformHideWindow(_GLFWwindow* window); void _glfwPlatformRequestWindowAttention(_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 3e8d5c5b..bb9d0fa0 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -582,6 +582,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 2e627672..a6be9a0b 100644 --- a/src/null_window.c +++ b/src/null_window.c @@ -189,6 +189,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 ef05898a..29c86a6e 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1328,6 +1328,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 b7498e1b..4ec7398c 100644 --- a/src/window.c +++ b/src/window.c @@ -708,6 +708,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 fbd58ffb..d0ca1f9f 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -612,6 +612,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 cdaac5f8..53b8bd0d 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 @@ -2143,6 +2144,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,