Support for drag and resize operations

This commit is contained in:
Robbin Marcus 2019-01-19 20:35:42 +01:00
parent 29d8ca4ce4
commit 073c0cceb5
10 changed files with 277 additions and 0 deletions

View File

@ -141,6 +141,10 @@ information on what to include when reporting a bug.
(#235,#439,#677,#845,#898)
- Added `glfwRequestWindowAttention` function for requesting attention from the
user (#732,#988)
- Added `glfwDragWindow` function for starting a drag operation on a window
(#987)
- Added `glfwResizeWindow` function for starting a resize operation on a window
(#923)
- Added `glfwGetKeyScancode` function that allows retrieving platform dependent
scancodes for keys (#830)
- Added `glfwSetWindowMaximizeCallback` and `GLFWwindowmaximizefun` for

View File

@ -1015,6 +1015,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.
*
@ -3192,6 +3201,54 @@ 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.3.
*
* @ingroup window
*/
GLFWAPI void glfwDragWindow(GLFWwindow* handle);
/*! @brief Starts a resize operation with the specified window.
*
* This function starts a resize operation on one of the borders of the
* specified window.
*
* this function must be called from a pointer or touch event callback,
* otherwise it risks reacting to a different event.
*
* 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 Requests user attention to the specified window.
*
* This function requests user attention to the specified window. On

View File

@ -1146,6 +1146,15 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window)
[window->ns.object makeKeyAndOrderFront:nil];
}
void _glfwPlatformDragWindow(_GLFWwindow* window)
{
[window->ns.object performWindowDragWithEvent:[NSApp currentEvent]];
}
void _glfwPlatformResizeWindow(_GLFWwindow* window, int border)
{
}
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
_GLFWmonitor* monitor,
int xpos, int ypos,

View File

@ -655,6 +655,8 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window);
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor,
int xpos, int ypos, int width, int height,
int refreshRate);
void _glfwPlatformDragWindow(_GLFWwindow* window);
void _glfwPlatformResizeWindow(_GLFWwindow* window, int border);
int _glfwPlatformWindowFocused(_GLFWwindow* window);
int _glfwPlatformWindowIconified(_GLFWwindow* window);
int _glfwPlatformWindowVisible(_GLFWwindow* window);

View File

@ -217,6 +217,14 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window)
{
}
void _glfwPlatformDragWindow(_GLFWwindow* window)
{
}
void _glfwPlatformResizeWindow(_GLFWwindow* window, int border)
{
}
int _glfwPlatformWindowFocused(_GLFWwindow* window)
{
return GLFW_FALSE;

View File

@ -33,6 +33,7 @@
#include <string.h>
#include <windowsx.h>
#include <shellapi.h>
#include <assert.h>
#define _GLFW_KEY_INVALID -2
@ -1656,6 +1657,48 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window)
SetFocus(window->win32.handle);
}
void _glfwPlatformDragWindow(_GLFWwindow* window)
{
ReleaseCapture();
SendMessage(window->win32.handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);
}
void _glfwPlatformResizeWindow(_GLFWwindow* window, int border)
{
WPARAM wBorder;
switch (border)
{
case GLFW_WINDOW_LEFT:
wBorder = HTLEFT;
break;
case GLFW_WINDOW_TOP:
wBorder = HTTOP;
break;
case GLFW_WINDOW_RIGHT:
wBorder = HTRIGHT;
break;
case GLFW_WINDOW_BOTTOM:
wBorder = HTBOTTOM;
break;
case GLFW_WINDOW_TOPLEFT:
wBorder = HTTOPLEFT;
break;
case GLFW_WINDOW_TOPRIGHT:
wBorder = HTTOPRIGHT;
break;
case GLFW_WINDOW_BOTTOMLEFT:
wBorder = HTBOTTOMLEFT;
break;
case GLFW_WINDOW_BOTTOMRIGHT:
wBorder = HTBOTTOMRIGHT;
break;
default:
assert(GLFW_FALSE);
}
ReleaseCapture();
SendMessage(window->win32.handle, WM_NCLBUTTONDOWN, wBorder, 0);
}
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
_GLFWmonitor* monitor,
int xpos, int ypos,

View File

@ -801,6 +801,29 @@ 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 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;

View File

@ -1215,6 +1215,49 @@ 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 _glfwPlatformResizeWindow(_GLFWwindow* window, int border)
{
int wlBorder;
switch (border)
{
case GLFW_WINDOW_LEFT:
wlBorder = WL_SHELL_SURFACE_RESIZE_LEFT;
break;
case GLFW_WINDOW_TOP:
wlBorder = WL_SHELL_SURFACE_RESIZE_TOP;
break;
case GLFW_WINDOW_RIGHT:
wlBorder = WL_SHELL_SURFACE_RESIZE_RIGHT;
break;
case GLFW_WINDOW_BOTTOM:
wlBorder = WL_SHELL_SURFACE_RESIZE_BOTTOM;
break;
case GLFW_WINDOW_TOPLEFT:
wlBorder = WL_SHELL_SURFACE_RESIZE_TOP_LEFT;
break;
case GLFW_WINDOW_TOPRIGHT:
wlBorder = WL_SHELL_SURFACE_RESIZE_TOP_RIGHT;
break;
case GLFW_WINDOW_BOTTOMLEFT:
wlBorder = WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT;
break;
case GLFW_WINDOW_BOTTOMRIGHT:
wlBorder = WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT;
break;
default:
assert(GLFW_FALSE);
}
wl_shell_surface_resize(window->wl.shellSurface,
_glfw.wl.seat,
_glfw.wl.pointerSerial,
wlBorder);
}
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
_GLFWmonitor* monitor,
int xpos, int ypos,

View File

@ -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
#define _NET_WM_MOVERESIZE_MOVE 8
// Additional mouse button names for XButtonEvent
#define Button6 6
@ -2388,6 +2397,78 @@ 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 _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;
break;
default:
assert(GLFW_FALSE);
}
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,

View File

@ -89,6 +89,12 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
}
}
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 i, ch;
@ -138,6 +144,7 @@ int main(int argc, char** argv)
}
glfwSetKeyCallback(windows[i], key_callback);
glfwSetMouseButtonCallback(windows[i], mouse_button_callback);
glfwMakeContextCurrent(windows[i]);
gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);