Move all cursor positioning to platform code

Due to Wayland, shared code cannot rely on cursor positioning being
supported by the underlying platform.

This implicitly fixes #617 as it moves cursor centering into
_glfwPlatformSetCursorMode, thus separating it from the stale value of
_glfw.cursorWindow.

Fixes #617.
This commit is contained in:
Camilla Berglund 2016-05-25 14:06:02 +02:00
parent 0e846883bf
commit 797ee8d8e3
12 changed files with 205 additions and 182 deletions

View File

@ -99,6 +99,8 @@ typedef struct _GLFWlibraryNS
short int publicKeys[256];
short int nativeKeys[GLFW_KEY_LAST + 1];
char* clipboardString;
// Where to place the cursor when re-enabled
double restoreCursorPosX, restoreCursorPosY;
struct {
CFBundleRef bundle;

View File

@ -85,6 +85,21 @@ static void centerCursor(_GLFWwindow *window)
_glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0);
}
// Updates the cursor image according to the specified cursor mode
//
static void updateCursorImage(_GLFWwindow* window, int mode)
{
if (mode == GLFW_CURSOR_NORMAL)
{
if (window->cursor)
[(NSCursor*) window->cursor->ns.object set];
else
[[NSCursor arrowCursor] set];
}
else
[(NSCursor*) _glfw.ns.cursor set];
}
// Transforms the specified y-coordinate between the CG display and NS screen
// coordinate systems
//
@ -394,7 +409,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
- (void)cursorUpdate:(NSEvent *)event
{
_glfwPlatformSetCursorMode(window, window->cursorMode);
updateCursorImage(window, window->cursorMode);
}
- (void)mouseDown:(NSEvent *)event
@ -422,16 +437,19 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
{
if (window->cursorMode == GLFW_CURSOR_DISABLED)
{
_glfwInputCursorMotion(window,
[event deltaX] - window->ns.cursorWarpDeltaX,
[event deltaY] - window->ns.cursorWarpDeltaY);
const double dx = [event deltaX] - window->ns.cursorWarpDeltaX;
const double dy = [event deltaY] - window->ns.cursorWarpDeltaY;
_glfwInputCursorPos(window,
window->virtualCursorPosX + dx,
window->virtualCursorPosY + dy);
}
else
{
const NSRect contentRect = [window->ns.view frame];
const NSPoint pos = [event locationInWindow];
_glfwInputCursorMotion(window, pos.x, contentRect.size.height - pos.y);
_glfwInputCursorPos(window, pos.x, contentRect.size.height - pos.y);
}
window->ns.cursorWarpDeltaX = 0;
@ -607,9 +625,9 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
NSArray* files = [pasteboard propertyListForType:NSFilenamesPboardType];
const NSRect contentRect = [window->ns.view frame];
_glfwInputCursorMotion(window,
[sender draggingLocation].x,
contentRect.size.height - [sender draggingLocation].y);
_glfwInputCursorPos(window,
[sender draggingLocation].x,
contentRect.size.height - [sender draggingLocation].y);
const int count = [files count];
if (count)
@ -1033,6 +1051,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
_glfwPlatformFocusWindow(window);
if (!acquireMonitor(window))
return GLFW_FALSE;
centerCursor(window);
}
return GLFW_TRUE;
@ -1397,7 +1417,7 @@ void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
{
_glfwPlatformSetCursorMode(window, window->cursorMode);
updateCursorImage(window, window->cursorMode);
const NSRect contentRect = [window->ns.view frame];
const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream];
@ -1423,20 +1443,23 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
{
if (mode == GLFW_CURSOR_NORMAL)
{
if (window->cursor)
[(NSCursor*) window->cursor->ns.object set];
else
[[NSCursor arrowCursor] set];
}
else
[(NSCursor*) _glfw.ns.cursor set];
if (mode == GLFW_CURSOR_DISABLED)
{
_glfwPlatformGetCursorPos(window,
&_glfw.ns.restoreCursorPosX,
&_glfw.ns.restoreCursorPosY);
centerCursor(window);
CGAssociateMouseAndMouseCursorPosition(false);
else
}
else if (window->cursorMode == GLFW_CURSOR_DISABLED)
{
CGAssociateMouseAndMouseCursorPosition(true);
_glfwPlatformSetCursorPos(window,
_glfw.ns.restoreCursorPosX,
_glfw.ns.restoreCursorPosY);
}
updateCursorImage(window, mode);
}
const char* _glfwPlatformGetKeyName(int key, int scancode)

View File

@ -37,48 +37,27 @@
// Sets the cursor mode for the specified window
//
static void setCursorMode(_GLFWwindow* window, int newMode)
static void setCursorMode(_GLFWwindow* window, int mode)
{
const int oldMode = window->cursorMode;
if (newMode != GLFW_CURSOR_NORMAL &&
newMode != GLFW_CURSOR_HIDDEN &&
newMode != GLFW_CURSOR_DISABLED)
if (mode != GLFW_CURSOR_NORMAL &&
mode != GLFW_CURSOR_HIDDEN &&
mode != GLFW_CURSOR_DISABLED)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid cursor mode %i", newMode);
_glfwInputError(GLFW_INVALID_ENUM, "Invalid cursor mode %i", mode);
return;
}
if (oldMode == newMode)
if (window->cursorMode == mode)
return;
window->cursorMode = newMode;
_glfwPlatformGetCursorPos(window,
&window->virtualCursorPosX,
&window->virtualCursorPosY);
if (_glfw.cursorWindow == window)
{
if (oldMode == GLFW_CURSOR_DISABLED)
{
_glfwPlatformSetCursorPos(window,
_glfw.restoreCursorPosX,
_glfw.restoreCursorPosY);
}
else if (newMode == GLFW_CURSOR_DISABLED)
{
int width, height;
_glfwPlatformSetCursorMode(window, mode);
_glfwPlatformGetCursorPos(window,
&_glfw.restoreCursorPosX,
&_glfw.restoreCursorPosY);
window->virtualCursorPosX = _glfw.restoreCursorPosX;
window->virtualCursorPosY = _glfw.restoreCursorPosY;
_glfwPlatformGetWindowSize(window, &width, &height);
_glfwPlatformSetCursorPos(window, width / 2, height / 2);
}
_glfwPlatformSetCursorMode(window, window->cursorMode);
}
window->cursorMode = mode;
}
// Set sticky keys mode for the specified window
@ -191,19 +170,13 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods);
}
void _glfwInputCursorMotion(_GLFWwindow* window, double x, double y)
void _glfwInputCursorPos(_GLFWwindow* window, double x, double y)
{
if (window->cursorMode == GLFW_CURSOR_DISABLED)
{
if (x == 0.0 && y == 0.0)
return;
if (window->virtualCursorPosX == x && window->virtualCursorPosY == y)
return;
window->virtualCursorPosX += x;
window->virtualCursorPosY += y;
x = window->virtualCursorPosX;
y = window->virtualCursorPosY;
}
window->virtualCursorPosX = x;
window->virtualCursorPosY = y;
if (window->callbacks.cursorPos)
window->callbacks.cursorPos((GLFWwindow*) window, x, y);
@ -490,9 +463,9 @@ GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle)
_GLFW_REQUIRE_INIT();
_glfwPlatformSetCursor(window, cursor);
window->cursor = cursor;
_glfwPlatformSetCursor(window, cursor);
}
GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun)

View File

@ -437,9 +437,6 @@ struct _GLFWlibrary
int refreshRate;
} hints;
// Where to place the cursor when re-enabled
double restoreCursorPosX, restoreCursorPosY;
_GLFWcursor* cursorListHead;
_GLFWwindow* windowListHead;
@ -906,7 +903,7 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
* of the client area of the window.
* @ingroup event
*/
void _glfwInputCursorMotion(_GLFWwindow* window, double x, double y);
void _glfwInputCursorPos(_GLFWwindow* window, double x, double y);
/*! @brief Notifies shared code of a cursor enter/leave event.
* @param[in] window The window that received the event.

View File

@ -208,8 +208,7 @@ static void handlePointerMotion(_GLFWwindow* window,
int dx = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll);
int dy = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll);
if (current_x != x || current_y != y)
_glfwInputCursorMotion(window, x, y);
_glfwInputCursorPos(window, x, y);
if (dx != 0 || dy != 0)
_glfwInputScroll(window, dx, dy);
}

View File

@ -252,6 +252,8 @@ typedef struct _GLFWlibraryWin32
char keyName[64];
short int publicKeys[512];
short int nativeKeys[GLFW_KEY_LAST + 1];
// Where to place the cursor when re-enabled
double restoreCursorPosX, restoreCursorPosY;
struct {
HINSTANCE instance;

View File

@ -218,15 +218,69 @@ static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area)
}
}
// Centers the cursor over the window client area
//
static void centerCursor(_GLFWwindow* window)
{
int width, height;
_glfwPlatformGetWindowSize(window, &width, &height);
_glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0);
}
//
//
static GLFWbool cursorInClientArea(_GLFWwindow* window)
{
RECT area;
POINT pos;
if (!GetCursorPos(&pos))
return GLFW_FALSE;
if (WindowFromPoint(pos) != window->win32.handle)
return GLFW_FALSE;
GetClientRect(window->win32.handle, &area);
ClientToScreen(window->win32.handle, (POINT*) &area.left);
ClientToScreen(window->win32.handle, (POINT*) &area.right);
return PtInRect(&area, pos);
}
// Updates the cursor image according to the specified cursor mode
//
static void updateCursorImage(_GLFWwindow* window, int mode)
{
if (mode == GLFW_CURSOR_NORMAL)
{
if (window->cursor)
SetCursor(window->cursor->win32.handle);
else
SetCursor(LoadCursorW(NULL, IDC_ARROW));
}
else
{
if (mode == GLFW_CURSOR_DISABLED && _glfw.cursorWindow != window)
SetCursor(LoadCursorW(NULL, IDC_ARROW));
else
SetCursor(NULL);
}
}
// Updates the cursor clip rect
//
static void updateClipRect(_GLFWwindow* window)
{
RECT clipRect;
GetClientRect(window->win32.handle, &clipRect);
ClientToScreen(window->win32.handle, (POINT*) &clipRect.left);
ClientToScreen(window->win32.handle, (POINT*) &clipRect.right);
ClipCursor(&clipRect);
if (window)
{
RECT clipRect;
GetClientRect(window->win32.handle, &clipRect);
ClientToScreen(window->win32.handle, (POINT*) &clipRect.left);
ClientToScreen(window->win32.handle, (POINT*) &clipRect.right);
ClipCursor(&clipRect);
}
else
ClipCursor(NULL);
}
// Translates a GLFW standard cursor to a resource ID
@ -420,10 +474,11 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
{
case WM_SETFOCUS:
{
_glfwInputWindowFocus(window, GLFW_TRUE);
if (window->cursorMode == GLFW_CURSOR_DISABLED)
_glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED);
_glfwInputWindowFocus(window, GLFW_TRUE);
return 0;
}
@ -571,12 +626,15 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
if (_glfw.cursorWindow != window)
break;
_glfwInputCursorMotion(window,
x - window->win32.lastCursorPosX,
y - window->win32.lastCursorPosY);
const int dx = x - window->win32.lastCursorPosX;
const int dy = y - window->win32.lastCursorPosY;
_glfwInputCursorPos(window,
window->virtualCursorPosX + dx,
window->virtualCursorPosY + dy);
}
else
_glfwInputCursorMotion(window, x, y);
_glfwInputCursorPos(window, x, y);
window->win32.lastCursorPosX = x;
window->win32.lastCursorPosY = y;
@ -725,19 +783,10 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
case WM_SETCURSOR:
{
if (_glfw.cursorWindow == window && LOWORD(lParam) == HTCLIENT)
if (LOWORD(lParam) == HTCLIENT)
{
if (window->cursorMode == GLFW_CURSOR_HIDDEN ||
window->cursorMode == GLFW_CURSOR_DISABLED)
{
SetCursor(NULL);
return TRUE;
}
else if (window->cursor)
{
SetCursor(window->cursor->win32.handle);
return TRUE;
}
updateCursorImage(window, window->cursorMode);
return TRUE;
}
break;
@ -767,7 +816,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
// Move the mouse to the position of the drop
DragQueryPoint(drop, &pt);
_glfwInputCursorMotion(window, pt.x, pt.y);
_glfwInputCursorPos(window, pt.x, pt.y);
for (i = 0; i < count; i++)
{
@ -1007,6 +1056,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
_glfwPlatformFocusWindow(window);
if (!acquireMonitor(window))
return GLFW_FALSE;
centerCursor(window);
}
return GLFW_TRUE;
@ -1444,28 +1495,24 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos)
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
{
POINT pos;
if (mode == GLFW_CURSOR_DISABLED)
updateClipRect(window);
else
ClipCursor(NULL);
if (!GetCursorPos(&pos))
return;
if (WindowFromPoint(pos) != window->win32.handle)
return;
if (mode == GLFW_CURSOR_NORMAL)
{
if (window->cursor)
SetCursor(window->cursor->win32.handle);
else
SetCursor(LoadCursorW(NULL, IDC_ARROW));
_glfwPlatformGetCursorPos(window,
&_glfw.win32.restoreCursorPosX,
&_glfw.win32.restoreCursorPosY);
centerCursor(window);
updateClipRect(window);
}
else
SetCursor(NULL);
else if (window->cursorMode == GLFW_CURSOR_DISABLED)
{
updateClipRect(NULL);
_glfwPlatformSetCursorPos(window,
_glfw.win32.restoreCursorPosX,
_glfw.win32.restoreCursorPosY);
}
if (cursorInClientArea(window))
updateCursorImage(window, mode);
}
const char* _glfwPlatformGetKeyName(int key, int scancode)
@ -1525,32 +1572,8 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
{
RECT area;
POINT pos;
if (_glfw.cursorWindow != window)
return;
if (window->cursorMode != GLFW_CURSOR_NORMAL)
return;
if (!GetCursorPos(&pos))
return;
if (WindowFromPoint(pos) != window->win32.handle)
return;
GetClientRect(window->win32.handle, &area);
ClientToScreen(window->win32.handle, (POINT*) &area.left);
ClientToScreen(window->win32.handle, (POINT*) &area.right);
if (!PtInRect(&area, pos))
return;
if (cursor)
SetCursor(cursor->win32.handle);
else
SetCursor(LoadCursorW(NULL, IDC_ARROW));
if (cursorInClientArea(window))
updateCursorImage(window, window->cursorMode);
}
void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)

View File

@ -219,19 +219,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
glfwMakeContextCurrent((GLFWwindow*) previous);
}
if (window->monitor)
{
int width, height;
_glfwPlatformGetWindowSize(window, &width, &height);
window->virtualCursorPosX = width / 2;
window->virtualCursorPosY = height / 2;
_glfwPlatformSetCursorPos(window,
window->virtualCursorPosX,
window->virtualCursorPosY);
}
else
if (!window->monitor)
{
if (wndconfig.visible)
{

View File

@ -91,9 +91,9 @@ static void pointerHandleMotion(void* data,
window->wl.cursorPosY = wl_fixed_to_double(sy);
}
_glfwInputCursorMotion(window,
wl_fixed_to_double(sx),
wl_fixed_to_double(sy));
_glfwInputCursorPos(window,
wl_fixed_to_double(sx),
wl_fixed_to_double(sy));
}
static void pointerHandleButton(void* data,

View File

@ -784,9 +784,9 @@ static void handleRelativeMotion(void* data,
if (window->cursorMode != GLFW_CURSOR_DISABLED)
return;
_glfwInputCursorMotion(window,
wl_fixed_to_double(dxUnaccel),
wl_fixed_to_double(dyUnaccel));
_glfwInputCursorPos(window,
window->virtualCursorPosX + wl_fixed_to_double(dxUnaccel),
window->virtualCursorPosY + wl_fixed_to_double(dyUnaccel));
}
static const struct zwp_relative_pointer_v1_listener relativePointerListener = {

View File

@ -118,7 +118,7 @@ typedef struct _GLFWwindowX11
int xpos, ypos;
// The last received cursor position, regardless of source
double lastCursorPosX, lastCursorPosY;
int lastCursorPosX, lastCursorPosY;
// The last position the cursor was warped to by GLFW
int warpCursorPosX, warpCursorPosY;
@ -155,6 +155,8 @@ typedef struct _GLFWlibraryX11
short int publicKeys[256];
// GLFW key to X11 keycode LUT
short int nativeKeys[GLFW_KEY_LAST + 1];
// Where to place the cursor when re-enabled
double restoreCursorPosX, restoreCursorPosY;
// Window manager atoms
Atom WM_PROTOCOLS;

View File

@ -387,6 +387,15 @@ static char** parseUriList(char* text, int* count)
return paths;
}
// Centers the cursor over the window client area
//
static void centerCursor(_GLFWwindow* window)
{
int width, height;
_glfwPlatformGetWindowSize(window, &width, &height);
_glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0);
}
// Create the X11 window (and its colormap)
//
static GLFWbool createWindow(_GLFWwindow* window,
@ -1158,12 +1167,15 @@ static void processEvent(XEvent *event)
if (_glfw.cursorWindow != window)
return;
_glfwInputCursorMotion(window,
x - window->x11.lastCursorPosX,
y - window->x11.lastCursorPosY);
const int dx = x - window->x11.lastCursorPosX;
const int dy = y - window->x11.lastCursorPosY;
_glfwInputCursorPos(window,
window->virtualCursorPosX + dx,
window->virtualCursorPosY + dy);
}
else
_glfwInputCursorMotion(window, x, y);
_glfwInputCursorPos(window, x, y);
}
window->x11.lastCursorPosX = x;
@ -1265,7 +1277,7 @@ static void processEvent(XEvent *event)
int x, y;
_glfwPlatformGetWindowPos(window, &x, &y);
_glfwInputCursorMotion(window, absX - x, absY - y);
_glfwInputCursorPos(window, absX - x, absY - y);
// Reply that we are ready to copy the dragged data
XEvent reply;
@ -1517,6 +1529,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
updateWindowMode(window);
if (!acquireMonitor(window))
return GLFW_FALSE;
centerCursor(window);
}
return GLFW_TRUE;
@ -1999,11 +2013,7 @@ void _glfwPlatformPollEvents(void)
_GLFWwindow* window = _glfw.cursorWindow;
if (window && window->cursorMode == GLFW_CURSOR_DISABLED)
{
int width, height;
_glfwPlatformGetWindowSize(window, &width, &height);
_glfwPlatformSetCursorPos(window, width / 2, height / 2);
}
centerCursor(window);
}
void _glfwPlatformWaitEvents(void)
@ -2082,31 +2092,35 @@ void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
{
if (mode == GLFW_CURSOR_DISABLED)
{
_glfwPlatformGetCursorPos(window,
&_glfw.x11.restoreCursorPosX,
&_glfw.x11.restoreCursorPosY);
centerCursor(window);
XGrabPointer(_glfw.x11.display, window->x11.handle, True,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
GrabModeAsync, GrabModeAsync,
window->x11.handle, _glfw.x11.cursor, CurrentTime);
}
else
else if (window->cursorMode == GLFW_CURSOR_DISABLED)
{
XUngrabPointer(_glfw.x11.display, CurrentTime);
_glfwPlatformSetCursorPos(window,
_glfw.x11.restoreCursorPosX,
_glfw.x11.restoreCursorPosY);
}
if (mode == GLFW_CURSOR_NORMAL)
{
if (window->cursor)
{
XDefineCursor(_glfw.x11.display, window->x11.handle,
window->cursor->x11.handle);
}
else
XUndefineCursor(_glfw.x11.display, window->x11.handle);
}
else
if (mode == GLFW_CURSOR_NORMAL)
{
if (window->cursor)
{
XDefineCursor(_glfw.x11.display, window->x11.handle,
_glfw.x11.cursor);
window->cursor->x11.handle);
}
else
XUndefineCursor(_glfw.x11.display, window->x11.handle);
}
else
XDefineCursor(_glfw.x11.display, window->x11.handle, _glfw.x11.cursor);
}
const char* _glfwPlatformGetKeyName(int key, int scancode)