From b9d2ea9fa6d58ee06ee49483c6831ddf36564736 Mon Sep 17 00:00:00 2001 From: Felipe Ferreira da Silva Date: Wed, 5 Apr 2017 22:14:09 -0300 Subject: [PATCH 1/6] Implementation of glfwDragWindow for X11 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. --- examples/simple.c | 7 +++++++ include/GLFW/glfw3.h | 19 +++++++++++++++++++ src/internal.h | 1 + src/window.c | 10 ++++++++++ src/x11_window.c | 19 +++++++++++++++++++ 5 files changed, 56 insertions(+) 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/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/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/x11_window.c b/src/x11_window.c index e1c2a3e3e..80f9f46c5 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,24 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) XFlush(_glfw.x11.display); } +void _glfwPlatformDragWindow(_GLFWwindow* window) +{ + XClientMessageEvent xclient; + memset(&xclient, 0, sizeof(XClientMessageEvent)); + XUngrabPointer(_glfw.x11.display, 0); + XFlush(_glfw.x11.display); + 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] = window->x11.xpos + window->x11.lastCursorPosX; + xclient.data.l[1] = window->x11.ypos + window->x11.lastCursorPosY; + 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, From 126e9a7b7097421972c5d73c4c95eab03644d537 Mon Sep 17 00:00:00 2001 From: Felipe Ferreira da Silva Date: Thu, 6 Apr 2017 11:11:30 -0300 Subject: [PATCH 2/6] Add implementation of glfwDragWindow for Windows The last parameter of ```SendMessage``` is set to 0, but possibly should be the cursor coordinates. Tests are required to know if it is the position of the cursor relative to the screen or to the specified window. --- src/null_window.c | 4 ++++ src/win32_window.c | 6 ++++++ 2 files changed, 10 insertions(+) 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, From c38b803b189b4935988a3d0c32fdcf301ba4dc91 Mon Sep 17 00:00:00 2001 From: Felipe Ferreira da Silva Date: Thu, 6 Apr 2017 13:57:12 -0300 Subject: [PATCH 3/6] Initial glfwDragWindow implementation for Wayland --- src/wl_window.c | 5 +++++ 1 file changed, 5 insertions(+) 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, From a96baa2d9981630a84c6dad2b06a13c0ceb6ed90 Mon Sep 17 00:00:00 2001 From: Felipe Ferreira da Silva Date: Thu, 6 Apr 2017 21:12:02 -0300 Subject: [PATCH 4/6] Add drag function for each platform Add stub functions ```_glfwPlatformDragWindow``` for the platforms Cocoa and Mir, which still lack the implementation of drag operation. --- src/cocoa_window.m | 4 ++++ src/mir_window.c | 4 ++++ 2 files changed, 8 insertions(+) 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/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, From f3cea803caffbbf8df2398fb2f8ef6ccac2dbdaf Mon Sep 17 00:00:00 2001 From: Felipe Ferreira da Silva Date: Thu, 6 Apr 2017 21:36:07 -0300 Subject: [PATCH 5/6] Mention the drag function in the README.md --- README.md | 1 + 1 file changed, 1 insertion(+) 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 From df8a36baebb8003f5173965ceaf356ad43c0b95d Mon Sep 17 00:00:00 2001 From: Felipe Ferreira da Silva Date: Fri, 7 Apr 2017 21:54:36 -0300 Subject: [PATCH 6/6] Check position of window and cursor before drag The previous implementation was using the stored window position and the stored last cursor position, but these should be updated. It's more reliable to get the current position of the window and cursor, otherwise the window might "jump" position during the start of a drag operation. --- src/x11_window.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/x11_window.c b/src/x11_window.c index 80f9f46c5..f83f44d57 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2094,16 +2094,20 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) 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] = window->x11.xpos + window->x11.lastCursorPosX; - xclient.data.l[1] = window->x11.ypos + window->x11.lastCursorPosY; + 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;