From b18eeed2256ee078e7ebfccdcf6a4d3131507067 Mon Sep 17 00:00:00 2001 From: Damien Plisson Date: Mon, 19 Oct 2009 10:49:45 +0000 Subject: [PATCH] Cocoa : - fix#19592 : implemented updated continuous grab feature (fixing compilation issues) - fix some 10.6 & 64bit warnings --- intern/ghost/intern/GHOST_SystemCocoa.h | 34 +---- intern/ghost/intern/GHOST_SystemCocoa.mm | 175 ++++++++++------------- intern/ghost/intern/GHOST_Window.h | 7 + intern/ghost/intern/GHOST_WindowCocoa.h | 10 +- intern/ghost/intern/GHOST_WindowCocoa.mm | 116 +++++++-------- 5 files changed, 146 insertions(+), 196 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h index ee7f9d8ed37..e880f851267 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.h +++ b/intern/ghost/intern/GHOST_SystemCocoa.h @@ -228,34 +228,7 @@ protected: * @return Indication whether the event was handled. */ GHOST_TSuccess handleKeyEvent(void *eventPtr); - - /** - * Handles all basic Mac application stuff for a mouse down event. - * @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++) - * @return Indication whether the event was handled. - */ - // bool handleMouseDown(void *eventPtr); - - /** - * Handles a Mac menu command. - * @param menuResult A Mac menu/item identifier. - * @return Indication whether the event was handled. - */ - // bool handleMenuCommand(GHOST_TInt32 menuResult); - /* callback for blender generated events */ -// static OSStatus blendEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData); - - - /** - * Callback for Mac Timer tasks that expire. - * @param tmTask Pointer to the timer task that expired. - */ - //static void s_timerCallback(TMTaskPtr tmTask); - - /** Event handler reference. */ - //EventHandlerRef m_handler; - /** Start time at initialization. */ GHOST_TUns64 m_start_time; @@ -266,7 +239,12 @@ protected: GHOST_TUns32 m_modifierMask; /** Ignores window size messages (when window is dragged). */ - bool m_ignoreWindowSizedMessages; + bool m_ignoreWindowSizedMessages; + + /** Stores the mouse cursor delta due to setting a new cursor position + * Needed because cocoa event delta cursor move takes setCursorPosition changes too. + */ + GHOST_TInt32 m_cursorDelta_x, m_cursorDelta_y; }; #endif // _GHOST_SYSTEM_COCOA_H_ diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 62f0c538e7e..f8e124991af 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -565,6 +565,8 @@ GHOST_SystemCocoa::GHOST_SystemCocoa() { m_modifierMask =0; m_pressedMouseButtons =0; + m_cursorDelta_x=0; + m_cursorDelta_y=0; m_displayManager = new GHOST_DisplayManagerCocoa (); GHOST_ASSERT(m_displayManager, "GHOST_SystemCocoa::GHOST_SystemCocoa(): m_displayManager==0\n"); m_displayManager->initialize(); @@ -873,15 +875,6 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent) if (timerMgr->fireTimers(getMilliSeconds())) { anyProcessed = true; - } - - if (getFullScreen()) { - // Check if the full-screen window is dirty - GHOST_IWindow* window = m_windowManager->getFullScreenWindow(); - if (((GHOST_WindowCarbon*)window)->getFullScreenDirty()) { - pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) ); - anyProcessed = true; - } }*/ do { @@ -999,6 +992,12 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType, GHOST_TUns8 GHOST_SystemCocoa::handleQuitRequest() { + GHOST_Window* window = (GHOST_Window*)m_windowManager->getActiveWindow(); + + //Discard quit event if we are in cursor grab sequence + if ((window->getCursorGrabMode() != GHOST_kGrabDisable) && (window->getCursorGrabMode() != GHOST_kGrabNormal)) + return GHOST_kExitCancel; + //Check open windows if some changes are not saved if (m_windowManager->getAnyModifiedState()) { @@ -1129,27 +1128,78 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) //No tablet event included : do nothing break; } + case NSMouseMoved: - { - if(window->getCursorWarp()) { - GHOST_TInt32 x_warp, y_warp, x_accum, y_accum; - - window->getCursorWarpPos(x_warp, y_warp); - - window->getCursorWarpAccum(x_accum, y_accum); - x_accum += [event deltaX]; - y_accum += -[event deltaY]; //Strange Apple implementation (inverted coordinates for the deltaY) ... - window->setCursorWarpAccum(x_accum, y_accum); - - pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, x_warp+x_accum, y_warp+y_accum)); - } - else { //Normal cursor operation: send mouse position in window - NSPoint mousePos = [event locationInWindow]; - pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, mousePos.x, mousePos.y)); - window->setCursorWarpAccum(0, 0); //Mouse motion occured between two cursor warps, so we can reset the delta counter + switch (window->getCursorGrabMode()) { + case GHOST_kGrabHide: //Cursor hidden grab operation : no cursor move + { + GHOST_TInt32 x_warp, y_warp, x_accum, y_accum; + + window->getCursorGrabInitPos(x_warp, y_warp); + + window->getCursorGrabAccum(x_accum, y_accum); + x_accum += [event deltaX]; + y_accum += -[event deltaY]; //Strange Apple implementation (inverted coordinates for the deltaY) ... + window->setCursorGrabAccum(x_accum, y_accum); + + pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, x_warp+x_accum, y_warp+y_accum)); + } + break; + case GHOST_kGrabWrap: //Wrap cursor at area/window boundaries + { + NSPoint mousePos = [event locationInWindow]; + GHOST_TInt32 x_mouse= mousePos.x; + GHOST_TInt32 y_mouse= mousePos.y; + GHOST_TInt32 x_accum, y_accum, x_cur, y_cur; + GHOST_Rect bounds, windowBounds, correctedBounds; + + /* fallback to window bounds */ + if(window->getCursorGrabBounds(bounds)==GHOST_kFailure) + window->getClientBounds(bounds); + + //Switch back to Cocoa coordinates orientation (y=0 at botton,the same as blender internal btw!), and to client coordinates + window->getClientBounds(windowBounds); + bounds.m_b = (windowBounds.m_b - windowBounds.m_t) - bounds.m_b; + bounds.m_t = (windowBounds.m_b - windowBounds.m_t) - bounds.m_t; + window->screenToClient(bounds.m_l,bounds.m_b, correctedBounds.m_l, correctedBounds.m_t); + window->screenToClient(bounds.m_r, bounds.m_t, correctedBounds.m_r, correctedBounds.m_b); + + //Update accumulation counts + window->getCursorGrabAccum(x_accum, y_accum); + x_accum += [event deltaX]-m_cursorDelta_x; + y_accum += -[event deltaY]-m_cursorDelta_y; //Strange Apple implementation (inverted coordinates for the deltaY) ... + window->setCursorGrabAccum(x_accum, y_accum); + + + //Warp mouse cursor if needed + x_mouse += [event deltaX]-m_cursorDelta_x; + y_mouse += -[event deltaY]-m_cursorDelta_y; + correctedBounds.wrapPoint(x_mouse, y_mouse, 2); + + //Compensate for mouse moved event taking cursor position set into account + m_cursorDelta_x = x_mouse-mousePos.x; + m_cursorDelta_y = y_mouse-mousePos.y; + + //Set new cursor position + window->clientToScreen(x_mouse, y_mouse, x_cur, y_cur); + setCursorPosition(x_cur, y_cur); /* wrap */ + + //Post event + window->getCursorGrabInitPos(x_cur, y_cur); + pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, x_cur + x_accum, y_cur + y_accum)); + } + break; + default: + { + //Normal cursor operation: send mouse position in window + NSPoint mousePos = [event locationInWindow]; + pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, mousePos.x, mousePos.y)); + m_cursorDelta_x=0; + m_cursorDelta_y=0; //Mouse motion occured between two cursor warps, so we can reset the delta counter + } + break; } break; - } case NSScrollWheel: { @@ -1323,74 +1373,3 @@ void GHOST_SystemCocoa::putClipboard(GHOST_TInt8 *buffer, bool selection) const [pool drain]; } - -#pragma mark Carbon stuff to remove - -#ifdef WITH_CARBON - - -OSErr GHOST_SystemCarbon::sAEHandlerLaunch(const AppleEvent *event, AppleEvent *reply, SInt32 refCon) -{ - //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon; - - return noErr; -} - -OSErr GHOST_SystemCarbon::sAEHandlerOpenDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon) -{ - //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon; - AEDescList docs; - SInt32 ndocs; - OSErr err; - - err = AEGetParamDesc(event, keyDirectObject, typeAEList, &docs); - if (err != noErr) return err; - - err = AECountItems(&docs, &ndocs); - if (err==noErr) { - int i; - - for (i=0; ipushEvent( new GHOST_Event(sys->getMilliSeconds(), GHOST_kEventQuit, NULL) ); - - return noErr; -} -#endif \ No newline at end of file diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index 0986fc57430..86447a8623c 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -159,6 +159,7 @@ public: */ inline virtual bool getCursorVisibility() const; inline virtual GHOST_TGrabCursorMode getCursorGrabMode() const; + inline virtual void getCursorGrabInitPos(GHOST_TInt32 &x, GHOST_TInt32 &y) const; inline virtual void getCursorGrabAccum(GHOST_TInt32 &x, GHOST_TInt32 &y) const; inline virtual void setCursorGrabAccum(GHOST_TInt32 x, GHOST_TInt32 y); @@ -327,6 +328,12 @@ inline GHOST_TGrabCursorMode GHOST_Window::getCursorGrabMode() const return m_cursorGrab; } +inline void GHOST_Window::getCursorGrabInitPos(GHOST_TInt32 &x, GHOST_TInt32 &y) const +{ + x = m_cursorGrabInitPos[0]; + y = m_cursorGrabInitPos[1]; +} + inline void GHOST_Window::getCursorGrabAccum(GHOST_TInt32 &x, GHOST_TInt32 &y) const { x= m_cursorGrabAccumPos[0]; diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h index e5fff75c66e..5368d0f1e13 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.h +++ b/intern/ghost/intern/GHOST_WindowCocoa.h @@ -236,18 +236,12 @@ protected: */ virtual GHOST_TSuccess setWindowCursorVisibility(bool visible); - /** - * Sets the cursor warp accumulator. Overriden for workaround due to Cocoa next event after cursor set giving delta values non zero - */ - inline virtual bool setCursorGrabAccum(GHOST_TInt32 x, GHOST_TInt32 y); - /** * Sets the cursor grab on the window using * native window system calls. - * @param warp Only used when grab is enabled, hides the mouse and allows gragging outside the screen. */ - virtual GHOST_TSuccess setWindowCursorGrab(bool grab, bool warp, bool restore); - + virtual GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode); + /** * Sets the cursor shape on the window using * native window system calls. diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index e41c773a4c3..c9b4fe40001 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -50,14 +50,27 @@ static NSOpenGLPixelFormatAttribute pixelFormatAttrsWindow[] = }; #pragma mark Cocoa window delegate object - +/* live resize ugly patch +extern "C" { + struct bContext; + typedef struct bContext bContext; + bContext* ghostC; + extern int wm_window_timer(const bContext *C); + extern void wm_window_process_events(const bContext *C); + extern void wm_event_do_handlers(bContext *C); + extern void wm_event_do_notifiers(bContext *C); + extern void wm_draw_update(bContext *C); +};*/ @interface CocoaWindowDelegate : NSObject +#ifdef MAC_OS_X_VERSION_10_6 + +#endif { GHOST_SystemCocoa *systemCocoa; GHOST_WindowCocoa *associatedWindow; } -- (void)setSystemAndWindowCocoa:(const GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa; +- (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa; - (void)windowWillClose:(NSNotification *)notification; - (void)windowDidBecomeKey:(NSNotification *)notification; - (void)windowDidResignKey:(NSNotification *)notification; @@ -97,7 +110,18 @@ static NSOpenGLPixelFormatAttribute pixelFormatAttrsWindow[] = - (void)windowDidResize:(NSNotification *)notification { - systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, associatedWindow); + if (![[notification object] inLiveResize]) { + //Send event only once, at end of resize operation (when user has released mouse button) + systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, associatedWindow); + } + /* Live resize ugly patch. Needed because live resize runs in a modal loop, not letting main loop run + if ([[notification object] inLiveResize]) { + systemCocoa->dispatchEvents(); + wm_window_timer(ghostC); + wm_event_do_handlers(ghostC); + wm_event_do_notifiers(ghostC); + wm_draw_update(ghostC); + }*/ } @end @@ -107,8 +131,6 @@ static NSOpenGLPixelFormatAttribute pixelFormatAttrsWindow[] = { } --(BOOL)canBecomeKeyWindow; - @end @implementation CocoaWindow @@ -125,7 +147,6 @@ static NSOpenGLPixelFormatAttribute pixelFormatAttrsWindow[] = //We need to subclass it in order to give Cocoa the feeling key events are trapped @interface CocoaOpenGLView : NSOpenGLView { - } @end @implementation CocoaOpenGLView @@ -515,6 +536,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state) //Make window borderless and enlarge it [m_window setStyleMask:NSBorderlessWindowMask]; [m_window setFrame:[[m_window screen] frame] display:YES]; + [m_window makeFirstResponder:m_openGLView]; #else //With 10.5, we need to create a new window to change its style to borderless //Hide menu & dock if needed @@ -572,6 +594,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state) //Make window normal and resize it [m_window setStyleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)]; [m_window setFrame:[[m_window screen] visibleFrame] display:YES]; + [m_window makeFirstResponder:m_openGLView]; #else //With 10.5, we need to create a new window to change its style to borderless //Show menu & dock if needed @@ -849,73 +872,42 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible) } -//Override this method to provide set feature even if not in warp -inline bool GHOST_WindowCocoa::setCursorWarpAccum(GHOST_TInt32 x, GHOST_TInt32 y) +GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode) { - m_cursorWarpAccumPos[0]= x; - m_cursorWarpAccumPos[1]= y; + GHOST_TSuccess err = GHOST_kSuccess; - return GHOST_kSuccess; -} - - -GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(bool grab, bool warp, bool restore) -{ - if (grab) + if (mode != GHOST_kGrabDisable) { //No need to perform grab without warp as it is always on in OS X - if(warp) { + if(mode != GHOST_kGrabNormal) { GHOST_TInt32 x_old,y_old; - m_cursorWarp= true; m_systemCocoa->getCursorPosition(x_old,y_old); - screenToClient(x_old, y_old, m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]); + screenToClient(x_old, y_old, m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]); //Warp position is stored in client (window base) coordinates - setWindowCursorVisibility(false); - return CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; + setCursorGrabAccum(0, 0); + + if(mode == GHOST_kGrabHide) { + setWindowCursorVisibility(false); + } + + //Dissociate cursor position even for warp mode, to allow mouse acceleration to work even when warping the cursor + err = CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; } } else { - if(m_cursorWarp) - {/* are we exiting warp */ + if(m_cursorGrab==GHOST_kGrabHide) + { + //No need to set again cursor position, as it has not changed for Cocoa 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_cur, y_cur; - - getClientBounds(bounds); - x_new= m_cursorWarpInitPos[0]+m_cursorWarpAccumPos[0]; - y_new= m_cursorWarpInitPos[1]+m_cursorWarpAccumPos[1]; - - if(x_new < 0) x_new = 0; - if(y_new < 0) y_new = 0; - if(x_new > bounds.getWidth()) x_new = bounds.getWidth(); - if(y_new > bounds.getHeight()) y_new = bounds.getHeight(); - - //get/set cursor position works in screen coordinates - clientToScreen(x_new, y_new, x_cur, y_cur); - m_systemCocoa->setCursorPosition(x_cur, y_cur); - - //As Cocoa will give as first deltaX,deltaY this change in cursor position, we need to compensate for it - //Issue appearing in case of two transform operations conducted w/o mouse motion in between - x_new=m_cursorWarpAccumPos[0]; - y_new=m_cursorWarpAccumPos[1]; - setCursorWarpAccum(-x_new, -y_new); - } - else { - GHOST_TInt32 x_new, y_new; - //get/set cursor position works in screen coordinates - clientToScreen(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1], x_new, y_new); - m_systemCocoa->setCursorPosition(x_new, y_new); - setCursorWarpAccum(0, 0); - } - - m_cursorWarp= false; - return CGAssociateMouseAndMouseCursorPosition(true) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; } + + err = CGAssociateMouseAndMouseCursorPosition(true) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; + /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */ + setCursorGrabAccum(0, 0); + m_cursorGrabBounds.m_l= m_cursorGrabBounds.m_r= -1; /* disable */ } - return GHOST_kSuccess; + return err; } GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape) @@ -979,7 +971,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 *bitmap samplesPerPixel:2 hasAlpha:YES isPlanar:YES - colorSpaceName:NSDeviceBlackColorSpace + colorSpaceName:NSDeviceWhiteColorSpace bytesPerRow:(sizex/8 + (sizex%8 >0 ?1:0)) bitsPerPixel:1]; @@ -989,10 +981,10 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 *bitmap for (y=0; y