- fix#19592 : implemented updated continuous grab feature (fixing compilation issues)
- fix some 10.6 & 64bit warnings
* @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;
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_
{
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();
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 {
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())
{
//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:
{
[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; i<ndocs; i++) {
- FSSpec fss;
- AEKeyword kwd;
- DescType actType;
- Size actSize;
-
- err = AEGetNthPtr(&docs, i+1, typeFSS, &kwd, &actType, &fss, sizeof(fss), &actSize);
- if (err!=noErr)
- break;
-
- if (i==0) {
- FSRef fsref;
-
- if (FSpMakeFSRef(&fss, &fsref)!=noErr)
- break;
- if (FSRefMakePath(&fsref, (UInt8*) g_firstFileBuf, sizeof(g_firstFileBuf))!=noErr)
- break;
-
- g_hasFirstFile = true;
- }
- }
- }
-
- AEDisposeDesc(&docs);
-
- return err;
-}
-
-OSErr GHOST_SystemCarbon::sAEHandlerPrintDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
-{
- //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
-
- return noErr;
-}
-
-OSErr GHOST_SystemCarbon::sAEHandlerQuit(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
-{
- GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
-
- sys->pushEvent( new GHOST_Event(sys->getMilliSeconds(), GHOST_kEventQuit, NULL) );
-
- return noErr;
-}
-#endif
\ No newline at end of file
*/
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);
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];
*/
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.
};
#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
+<NSWindowDelegate>
+#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;
- (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
{
}
--(BOOL)canBecomeKeyWindow;
-
@end
@implementation CocoaWindow
//We need to subclass it in order to give Cocoa the feeling key events are trapped
@interface CocoaOpenGLView : NSOpenGLView
{
-
}
@end
@implementation CocoaOpenGLView
//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
//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
}
-//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)
samplesPerPixel:2
hasAlpha:YES
isPlanar:YES
- colorSpaceName:NSDeviceBlackColorSpace
+ colorSpaceName:NSDeviceWhiteColorSpace
bytesPerRow:(sizex/8 + (sizex%8 >0 ?1:0))
bitsPerPixel:1];
for (y=0; y<nbUns16; y++) {
#if !defined(__LITTLE_ENDIAN__)
- cursorBitmap[y] = uns16ReverseBits((bitmap[2*y]<<0) | (bitmap[2*y+1]<<8));
+ cursorBitmap[y] = ~uns16ReverseBits((bitmap[2*y]<<0) | (bitmap[2*y+1]<<8));
cursorBitmap[nbUns16+y] = uns16ReverseBits((mask[2*y]<<0) | (mask[2*y+1]<<8));
#else
- cursorBitmap[y] = uns16ReverseBits((bitmap[2*y+1]<<0) | (bitmap[2*y]<<8));
+ cursorBitmap[y] = ~uns16ReverseBits((bitmap[2*y+1]<<0) | (bitmap[2*y]<<8));
cursorBitmap[nbUns16+y] = uns16ReverseBits((mask[2*y+1]<<0) | (mask[2*y]<<8));
#endif