diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 00d2cdb1e3b..93bd12437ab 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -376,7 +376,7 @@ extern GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, * @return Indication of success. */ extern GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle, - int grab, int warp, int restore); + GHOST_TGrabCursorMode mode); /*************************************************************************************** ** Access to mouse button and keyboard states. diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index 993b41a4d4f..3ab9bef2bfa 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -271,7 +271,7 @@ public: * @param grab The new grab state of the cursor. * @return Indication of success. */ - virtual GHOST_TSuccess setCursorGrab(bool grab, bool warp, bool restore) { return GHOST_kSuccess; }; + virtual GHOST_TSuccess setCursorGrab(GHOST_TGrabCursorMode mode) { return GHOST_kSuccess; }; }; diff --git a/intern/ghost/GHOST_Rect.h b/intern/ghost/GHOST_Rect.h index 6271ecad408..98169ad2aa4 100644 --- a/intern/ghost/GHOST_Rect.h +++ b/intern/ghost/GHOST_Rect.h @@ -126,6 +126,13 @@ public: */ virtual inline void unionPoint(GHOST_TInt32 x, GHOST_TInt32 y); + /** + * Grows the rectangle to included a point. + * @param x The x-coordinate of the point. + * @param y The y-coordinate of the point. + */ + virtual inline void wrapPoint(GHOST_TInt32 &x, GHOST_TInt32 &y, GHOST_TInt32 ofs); + /** * Returns whether the point is inside this rectangle. * Point on the boundary is considered inside. @@ -222,6 +229,21 @@ inline void GHOST_Rect::unionPoint(GHOST_TInt32 x, GHOST_TInt32 y) if (y > m_b) m_b = y; } +inline void GHOST_Rect::wrapPoint(GHOST_TInt32 &x, GHOST_TInt32 &y, GHOST_TInt32 ofs) +{ + GHOST_TInt32 w= getWidth(); + GHOST_TInt32 h= getHeight(); + + /* highly unlikely but avoid eternal loop */ + if(w-ofs <= 0 || h-ofs <= 0) + return; + + while(x-ofs < m_l) x+= w; + while(y-ofs < m_t) y+= h; + while(x+ofs > m_r) x-= w; + while(y+ofs > m_b) y-= h; +} + inline bool GHOST_Rect::isInside(GHOST_TInt32 x, GHOST_TInt32 y) const { return (x >= m_l) && (x <= m_r) && (y >= m_t) && (y <= m_b); diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 14e3c4bb5f7..e98e58740ad 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -341,6 +341,12 @@ typedef enum { GHOST_kKeyF24 } GHOST_TKey; +typedef enum { + GHOST_kGrabDisable = 0, /* grab not set */ + GHOST_kGrabNormal, /* no cursor adjustments */ + GHOST_kGrabWrap, /* wrap the mouse location to prevent limiting screen bounds */ + GHOST_kGrabHide, /* hide the mouse while grabbing and restore the original location on release (numbuts) */ +} GHOST_TGrabCursorMode; typedef void* GHOST_TEventDataPtr; diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index e225ad4fd90..5563e0d1aa8 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -355,11 +355,11 @@ GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle, - int grab, int warp, int restore) + GHOST_TGrabCursorMode mode) { GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; - return window->setCursorGrab(grab?true:false, warp?true:false, restore?true:false); + return window->setCursorGrab(mode); } diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 8c87abf16bc..abf0b612f9a 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -388,31 +388,36 @@ GHOST_SystemX11::processEvent(XEvent *xe) { XMotionEvent &xme = xe->xmotion; - if(window->getCursorWarp()) { - /* Calculate offscreen location and re-center the mouse */ - GHOST_TInt32 x_warp, y_warp, x_new, y_new, x_accum, y_accum; + if(window->getCursorGrabMode() != GHOST_kGrabDisable && window->getCursorGrabMode() != GHOST_kGrabNormal) + { + GHOST_TInt32 x_new= xme.x_root; + GHOST_TInt32 y_new= xme.y_root; + GHOST_TInt32 x_accum, y_accum; + GHOST_Rect bounds; - window->getCursorWarpPos(x_warp, y_warp); - getCursorPosition(x_new, y_new); + window->getClientBounds(bounds); - if(x_warp != x_new || y_warp != y_new) { - window->getCursorWarpAccum(x_accum, y_accum); - x_accum += x_new - x_warp; - y_accum += y_new - y_warp; + /* could also clamp to screen bounds + * wrap with a window outside the view will fail atm */ - window->setCursorWarpAccum(x_accum, y_accum); - setCursorPosition(x_warp, y_warp); /* reset */ + bounds.wrapPoint(x_new, y_new, 1); /* offset of one incase blender is at screen bounds */ - g_event = new - GHOST_EventCursor( - getMilliSeconds(), - GHOST_kEventCursorMove, - window, - x_warp + x_accum, - y_warp + y_accum - ); + window->getCursorGrabAccum(x_accum, y_accum); + if(x_new != xme.x_root || y_new != xme.y_root) { + setCursorPosition(x_new, y_new); /* wrap */ + window->setCursorGrabAccum(x_accum + (xme.x_root - x_new), y_accum + (xme.y_root - y_new)); } + + g_event = new + GHOST_EventCursor( + getMilliSeconds(), + GHOST_kEventCursorMove, + window, + xme.x_root + x_accum, + xme.y_root + y_accum + ); + } else { g_event = new diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp index 94feb83e003..cda6bfa06ee 100644 --- a/intern/ghost/intern/GHOST_Window.cpp +++ b/intern/ghost/intern/GHOST_Window.cpp @@ -48,15 +48,14 @@ GHOST_Window::GHOST_Window( : m_drawingContextType(type), m_cursorVisible(true), - m_cursorGrabbed(false), - m_cursorWarp(false), + m_cursorGrab(GHOST_kGrabDisable), m_cursorShape(GHOST_kStandardCursorDefault), m_stereoVisual(stereoVisual) { m_isUnsavedChanges = false; - m_cursorWarpAccumPos[0] = 0; - m_cursorWarpAccumPos[1] = 0; + m_cursorGrabAccumPos[0] = 0; + m_cursorGrabAccumPos[1] = 0; m_fullScreen = state == GHOST_kWindowStateFullScreen; if (m_fullScreen) { @@ -98,13 +97,13 @@ GHOST_TSuccess GHOST_Window::setCursorVisibility(bool visible) } } -GHOST_TSuccess GHOST_Window::setCursorGrab(bool grab, bool warp, bool restore) +GHOST_TSuccess GHOST_Window::setCursorGrab(GHOST_TGrabCursorMode mode) { - if(m_cursorGrabbed == grab) + if(m_cursorGrab == mode) return GHOST_kSuccess; - if (setWindowCursorGrab(grab, warp, restore)) { - m_cursorGrabbed = grab; + if (setWindowCursorGrab(mode)) { + m_cursorGrab = mode; return GHOST_kSuccess; } else { diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index 786918716c5..e66a3c2fd36 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -158,10 +158,9 @@ public: * @return The visibility state of the cursor. */ inline virtual bool getCursorVisibility() const; - inline virtual bool getCursorWarp() const; - inline virtual bool getCursorWarpPos(GHOST_TInt32 &x, GHOST_TInt32 &y) const; - inline virtual bool getCursorWarpAccum(GHOST_TInt32 &x, GHOST_TInt32 &y) const; - inline virtual bool setCursorWarpAccum(GHOST_TInt32 x, GHOST_TInt32 y); + inline virtual GHOST_TGrabCursorMode getCursorGrabMode() const; + inline virtual void getCursorGrabAccum(GHOST_TInt32 &x, GHOST_TInt32 &y) const; + inline virtual void setCursorGrabAccum(GHOST_TInt32 x, GHOST_TInt32 y); /** * Shows or hides the cursor. @@ -175,7 +174,7 @@ public: * @param grab The new grab state of the cursor. * @return Indication of success. */ - virtual GHOST_TSuccess setCursorGrab(bool grab, bool warp, bool restore); + virtual GHOST_TSuccess setCursorGrab(GHOST_TGrabCursorMode mode); /** * Sets the window "modified" status, indicating unsaved changes @@ -247,7 +246,7 @@ protected: * Sets the cursor grab on the window using * native window system calls. */ - virtual GHOST_TSuccess setWindowCursorGrab(bool grab, bool warp, bool restore) { return GHOST_kSuccess; }; + virtual GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) { return GHOST_kSuccess; }; /** * Sets the cursor shape on the window using @@ -274,16 +273,13 @@ protected: bool m_cursorVisible; /** The current grabbed state of the cursor */ - bool m_cursorGrabbed; - - /** The current warped state of the cursor */ - bool m_cursorWarp; + GHOST_TGrabCursorMode m_cursorGrab; /** Initial grab location. */ - GHOST_TInt32 m_cursorWarpInitPos[2]; + GHOST_TInt32 m_cursorGrabInitPos[2]; - /** Accumulated offset from m_cursorWarpInitPos. */ - GHOST_TInt32 m_cursorWarpAccumPos[2]; + /** Accumulated offset from m_cursorGrabInitPos. */ + GHOST_TInt32 m_cursorGrabAccumPos[2]; /** The current shape of the cursor */ GHOST_TStandardCursor m_cursorShape; @@ -317,40 +313,21 @@ inline bool GHOST_Window::getCursorVisibility() const return m_cursorVisible; } -inline bool GHOST_Window::getCursorWarp() const +inline GHOST_TGrabCursorMode GHOST_Window::getCursorGrabMode() const { - return m_cursorWarp; + return m_cursorGrab; } -inline bool GHOST_Window::getCursorWarpPos(GHOST_TInt32 &x, GHOST_TInt32 &y) const +inline void GHOST_Window::getCursorGrabAccum(GHOST_TInt32 &x, GHOST_TInt32 &y) const { - if(m_cursorWarp==false) - return GHOST_kFailure; - - x= m_cursorWarpInitPos[0]; - y= m_cursorWarpInitPos[1]; - return GHOST_kSuccess; + x= m_cursorGrabAccumPos[0]; + y= m_cursorGrabAccumPos[1]; } -inline bool GHOST_Window::getCursorWarpAccum(GHOST_TInt32 &x, GHOST_TInt32 &y) const +inline void GHOST_Window::setCursorGrabAccum(GHOST_TInt32 x, GHOST_TInt32 y) { - if(m_cursorWarp==false) - return GHOST_kFailure; - - x= m_cursorWarpAccumPos[0]; - y= m_cursorWarpAccumPos[1]; - return GHOST_kSuccess; -} - -inline bool GHOST_Window::setCursorWarpAccum(GHOST_TInt32 x, GHOST_TInt32 y) -{ - if(m_cursorWarp==false) - return GHOST_kFailure; - - m_cursorWarpAccumPos[0]= x; - m_cursorWarpAccumPos[1]= y; - - return GHOST_kSuccess; + m_cursorGrabAccumPos[0]= x; + m_cursorGrabAccumPos[1]= y; } inline GHOST_TStandardCursor GHOST_Window::getCursorShape() const diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h index d6c154535a9..e5fff75c66e 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.h +++ b/intern/ghost/intern/GHOST_WindowCocoa.h @@ -239,7 +239,7 @@ protected: /** * Sets the cursor warp accumulator. Overriden for workaround due to Cocoa next event after cursor set giving delta values non zero */ - inline virtual bool setCursorWarpAccum(GHOST_TInt32 x, GHOST_TInt32 y); + inline virtual bool setCursorGrabAccum(GHOST_TInt32 x, GHOST_TInt32 y); /** * Sets the cursor grab on the window using diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index d197b534352..9914bad23c8 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -1400,47 +1400,27 @@ setWindowCursorVisibility( GHOST_TSuccess GHOST_WindowX11:: setWindowCursorGrab( - bool grab, bool warp, bool restore + GHOST_TGrabCursorMode mode ){ - if(grab) { - if(warp) { - m_system->getCursorPosition(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]); + if(mode != GHOST_kGrabDisable) { + if(mode != GHOST_kGrabNormal) { + m_system->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]); + setCursorGrabAccum(0, 0); + + if(mode == GHOST_kGrabHide) + setWindowCursorVisibility(false); - setCursorWarpAccum(0, 0); - setWindowCursorVisibility(false); - m_cursorWarp= true; } XGrabPointer(m_display, m_window, True, ButtonPressMask| ButtonReleaseMask|PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); } else { - if(m_cursorWarp) { /* are we exiting warp */ + if (m_cursorGrab==GHOST_kGrabHide) { + m_system->setCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]); setWindowCursorVisibility(true); - /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */ - if(restore) { - GHOST_Rect bounds; - GHOST_TInt32 x_new, y_new, x_rel, y_rel; - - getClientBounds(bounds); - - x_new= m_cursorWarpInitPos[0]+m_cursorWarpAccumPos[0]; - y_new= m_cursorWarpInitPos[1]+m_cursorWarpAccumPos[1]; - - screenToClient(x_new, y_new, x_rel, y_rel); - - if(x_rel < 0) x_new = (x_new-x_rel) + 2; - if(y_rel < 0) y_new = (y_new-y_rel) + 2; - if(x_rel > bounds.getWidth()) x_new -= (x_rel-bounds.getWidth()) + 2; - if(y_rel > bounds.getHeight()) y_new -= (y_rel-bounds.getHeight()) + 2; - m_system->setCursorPosition(x_new, y_new); - - } - else { - m_system->setCursorPosition(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]); - } - - setCursorWarpAccum(0, 0); - m_cursorWarp= false; } + + /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */ + setCursorGrabAccum(0, 0); XUngrabPointer(m_display, CurrentTime); } diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index eb0689ab410..0dba1776553 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -256,9 +256,12 @@ protected: */ GHOST_TSuccess setWindowCursorGrab( - bool grab, bool warp, bool restore + GHOST_TGrabCursorMode mode ); + GHOST_TGrabCursorMode + getWindowCursorGrab() const; + /** * Sets the cursor shape on the window using * native window system calls. diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 479c72304b2..bce38066899 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -3723,12 +3723,12 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s /* number editing */ if(state == BUTTON_STATE_NUM_EDITING) { if(ui_is_a_warp_but(but)) - WM_cursor_grab(CTX_wm_window(C), TRUE); + WM_cursor_grab(CTX_wm_window(C), TRUE, TRUE); ui_numedit_begin(but, data); } else if(data->state == BUTTON_STATE_NUM_EDITING) { ui_numedit_end(but, data); if(ui_is_a_warp_but(but)) - WM_cursor_ungrab(CTX_wm_window(C), FALSE); + WM_cursor_ungrab(CTX_wm_window(C)); } /* menu open */ if(state == BUTTON_STATE_MENU_OPEN) diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 958b388f574..d90d812d0bb 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -76,8 +76,8 @@ void WM_cursor_set (struct wmWindow *win, int curs); void WM_cursor_modal (struct wmWindow *win, int curs); void WM_cursor_restore (struct wmWindow *win); void WM_cursor_wait (int val); -void WM_cursor_grab(struct wmWindow *win, int warp); -void WM_cursor_ungrab(wmWindow *win, int restore); +void WM_cursor_grab(struct wmWindow *win, int wrap, int hide); +void WM_cursor_ungrab(struct wmWindow *win); void WM_timecursor (struct wmWindow *win, int nr); void *WM_paint_cursor_activate(struct wmWindowManager *wm, int (*poll)(struct bContext *C), void (*draw)(struct bContext *C, int, int, void *customdata), void *customdata); diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index c1dfd9ee9fb..1d5b10f2583 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -163,21 +163,26 @@ void WM_cursor_wait(int val) } } -void WM_cursor_grab(wmWindow *win, int warp) +void WM_cursor_grab(wmWindow *win, int wrap, int hide) { /* Only grab cursor when not running debug. * It helps not to get a stuck WM when hitting a breakpoint * */ + GHOST_TGrabCursorMode mode = GHOST_kGrabNormal; + + if(hide) mode = GHOST_kGrabHide; + else if(wrap) mode = GHOST_kGrabWrap; + if ((G.f & G_DEBUG) == 0) if(win) - GHOST_SetCursorGrab(win->ghostwin, 1, warp, -1); + GHOST_SetCursorGrab(win->ghostwin, mode); } -void WM_cursor_ungrab(wmWindow *win, int restore) +void WM_cursor_ungrab(wmWindow *win) { if ((G.f & G_DEBUG) == 0) if(win) - GHOST_SetCursorGrab(win->ghostwin, 0, -1, restore); + GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable); } /* afer this you can call restore too */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index f1104feaf5b..9e5f982880e 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -464,7 +464,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P /* grab cursor during blocking modal ops (X11) */ if(ot->flag & OPTYPE_BLOCKING) { int warp = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->flag & OP_GRAB_POINTER) || (ot->flag & OPTYPE_GRAB_POINTER)); - WM_cursor_grab(CTX_wm_window(C), warp); + WM_cursor_grab(CTX_wm_window(C), warp, FALSE); } } else @@ -660,7 +660,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers) CTX_wm_region_set(C, region); } - WM_cursor_ungrab(CTX_wm_window(C), TRUE); + WM_cursor_ungrab(CTX_wm_window(C)); WM_operator_free(handler->op); } else if(handler->ui_remove) { @@ -858,7 +858,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand /* remove modal handler, operator itself should have been cancelled and freed */ if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) { - WM_cursor_ungrab(CTX_wm_window(C), TRUE); + WM_cursor_ungrab(CTX_wm_window(C)); BLI_remlink(handlers, handler); wm_event_free_handler(handler);