/** * $Id: GHOST_WindowCocoa.mm 23275 2009-09-16 15:55:00Z campbellbarton $ * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** */ /** * $Id: GHOST_WindowCocoa.mm 23275 2009-09-16 15:55:00Z campbellbarton $ * Copyright (C) 2001 NaN Technologies B.V. * @author Maarten Gribnau * @date May 10, 2001 */ #ifdef HAVE_CONFIG_H #include #endif #include #include "GHOST_WindowCocoa.h" #include "GHOST_Debug.h" AGLContext GHOST_WindowCocoa::s_firstaglCtx = NULL; #ifdef GHOST_DRAW_CARBON_GUTTER const GHOST_TInt32 GHOST_WindowCocoa::s_sizeRectSize = 16; #endif //GHOST_DRAW_CARBON_GUTTER static const GLint sPreferredFormatWindow[8] = { AGL_RGBA, AGL_DOUBLEBUFFER, AGL_ACCELERATED, AGL_DEPTH_SIZE, 32, AGL_NONE, }; static const GLint sPreferredFormatFullScreen[9] = { AGL_RGBA, AGL_DOUBLEBUFFER, AGL_ACCELERATED, AGL_FULLSCREEN, AGL_DEPTH_SIZE, 32, AGL_NONE, }; WindowRef ugly_hack=NULL; const EventTypeSpec kWEvents[] = { { kEventClassWindow, kEventWindowZoom }, /* for new zoom behaviour */ }; static OSStatus myWEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData) { WindowRef mywindow; GHOST_WindowCocoa *ghost_window; OSStatus err; int theState; if (::GetEventKind(event) == kEventWindowZoom) { err = ::GetEventParameter (event,kEventParamDirectObject,typeWindowRef,NULL,sizeof(mywindow),NULL, &mywindow); ghost_window = (GHOST_WindowCocoa *) GetWRefCon(mywindow); theState = ghost_window->getMac_windowState(); if (theState == 1) ghost_window->setMac_windowState(2); else if (theState == 2) ghost_window->setMac_windowState(1); } return eventNotHandledErr; } GHOST_WindowCocoa::GHOST_WindowCocoa( const STR_String& title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height, GHOST_TWindowState state, GHOST_TDrawingContextType type, const bool stereoVisual ) : GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone), m_windowRef(0), m_grafPtr(0), m_aglCtx(0), m_customCursor(0), m_fullScreenDirty(false) { Str255 title255; OSStatus err; //fprintf(stderr," main screen top %i left %i height %i width %i\n", top, left, height, width); if (state >= GHOST_kWindowState8Normal ) { if(state == GHOST_kWindowState8Normal) state= GHOST_kWindowStateNormal; else if(state == GHOST_kWindowState8Maximized) state= GHOST_kWindowStateMaximized; else if(state == GHOST_kWindowState8Minimized) state= GHOST_kWindowStateMinimized; else if(state == GHOST_kWindowState8FullScreen) state= GHOST_kWindowStateFullScreen; // state = state - 8; this was the simple version of above code, doesnt work in gcc 4.0 setMac_windowState(1); } else setMac_windowState(0); if (state != GHOST_kWindowStateFullScreen) { Rect bnds = { top, left, top+height, left+width }; // Boolean visible = (state == GHOST_kWindowStateNormal) || (state == GHOST_kWindowStateMaximized); /*unused*/ gen2mac(title, title255); err = ::CreateNewWindow( kDocumentWindowClass, kWindowStandardDocumentAttributes+kWindowLiveResizeAttribute, &bnds, &m_windowRef); if ( err != noErr) { fprintf(stderr," error creating window %i \n",err); } else { ::SetWRefCon(m_windowRef,(SInt32)this); setTitle(title); err = InstallWindowEventHandler (m_windowRef, myWEventHandlerProc, GetEventTypeCount(kWEvents), kWEvents,NULL,NULL); if ( err != noErr) { fprintf(stderr," error creating handler %i \n",err); } else { // ::TransitionWindow (m_windowRef,kWindowZoomTransitionEffect,kWindowShowTransitionAction,NULL); ::ShowWindow(m_windowRef); ::MoveWindow (m_windowRef, left, top,true); } } if (m_windowRef) { m_grafPtr = ::GetWindowPort(m_windowRef); setDrawingContextType(type); updateDrawingContext(); activateDrawingContext(); } if(ugly_hack==NULL) { ugly_hack= m_windowRef; // when started from commandline, window remains in the back... also for play anim ProcessSerialNumber psn; GetCurrentProcess(&psn); SetFrontProcess(&psn); } } else { /* Rect bnds = { top, left, top+height, left+width }; gen2mac("", title255); m_windowRef = ::NewCWindow( nil, // Storage &bnds, // Bounding rectangle of the window title255, // Title of the window 0, // Window initially visible plainDBox, // procID (WindowRef)-1L, // Put window before all other windows 0, // Window has minimize box (SInt32)this); // Store a pointer to the class in the refCon */ //GHOST_PRINT("GHOST_WindowCocoa::GHOST_WindowCocoa(): creating full-screen OpenGL context\n"); setDrawingContextType(GHOST_kDrawingContextTypeOpenGL);;installDrawingContext(GHOST_kDrawingContextTypeOpenGL); updateDrawingContext(); activateDrawingContext(); m_tablet.Active = GHOST_kTabletModeNone; } } GHOST_WindowCocoa::~GHOST_WindowCocoa() { if (m_customCursor) delete m_customCursor; if(ugly_hack==m_windowRef) ugly_hack= NULL; // printf("GHOST_WindowCocoa::~GHOST_WindowCocoa(): removing drawing context\n"); if(ugly_hack==NULL) setDrawingContextType(GHOST_kDrawingContextTypeNone); if (m_windowRef) { ::DisposeWindow(m_windowRef); m_windowRef = 0; } } bool GHOST_WindowCocoa::getValid() const { bool valid; if (!m_fullScreen) { valid = (m_windowRef != 0) && (m_grafPtr != 0) && ::IsValidWindowPtr(m_windowRef); } else { valid = true; } return valid; } void GHOST_WindowCocoa::setTitle(const STR_String& title) { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setTitle(): window invalid") Str255 title255; gen2mac(title, title255); ::SetWTitle(m_windowRef, title255); } void GHOST_WindowCocoa::getTitle(STR_String& title) const { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getTitle(): window invalid") Str255 title255; ::GetWTitle(m_windowRef, title255); mac2gen(title255, title); } void GHOST_WindowCocoa::getWindowBounds(GHOST_Rect& bounds) const { OSStatus success; Rect rect; GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getWindowBounds(): window invalid") success = ::GetWindowBounds(m_windowRef, kWindowStructureRgn, &rect); bounds.m_b = rect.bottom; bounds.m_l = rect.left; bounds.m_r = rect.right; bounds.m_t = rect.top; } void GHOST_WindowCocoa::getClientBounds(GHOST_Rect& bounds) const { Rect rect; GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getClientBounds(): window invalid") //::GetPortBounds(m_grafPtr, &rect); ::GetWindowBounds(m_windowRef, kWindowContentRgn, &rect); bounds.m_b = rect.bottom; bounds.m_l = rect.left; bounds.m_r = rect.right; bounds.m_t = rect.top; // Subtract gutter height from bottom #ifdef GHOST_DRAW_CARBON_GUTTER if ((bounds.m_b - bounds.m_t) > s_sizeRectSize) { bounds.m_b -= s_sizeRectSize; } else { bounds.m_t = bounds.m_b; } #endif //GHOST_DRAW_CARBON_GUTTER } GHOST_TSuccess GHOST_WindowCocoa::setClientWidth(GHOST_TUns32 width) { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientWidth(): window invalid") GHOST_Rect cBnds, wBnds; getClientBounds(cBnds); if (((GHOST_TUns32)cBnds.getWidth()) != width) { ::SizeWindow(m_windowRef, width, cBnds.getHeight(), true); } return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowCocoa::setClientHeight(GHOST_TUns32 height) { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientHeight(): window invalid") GHOST_Rect cBnds, wBnds; getClientBounds(cBnds); #ifdef GHOST_DRAW_CARBON_GUTTER if (((GHOST_TUns32)cBnds.getHeight()) != height+s_sizeRectSize) { ::SizeWindow(m_windowRef, cBnds.getWidth(), height+s_sizeRectSize, true); } #else //GHOST_DRAW_CARBON_GUTTER if (((GHOST_TUns32)cBnds.getHeight()) != height) { ::SizeWindow(m_windowRef, cBnds.getWidth(), height, true); } #endif //GHOST_DRAW_CARBON_GUTTER return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowCocoa::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientSize(): window invalid") GHOST_Rect cBnds, wBnds; getClientBounds(cBnds); #ifdef GHOST_DRAW_CARBON_GUTTER if ((((GHOST_TUns32)cBnds.getWidth()) != width) || (((GHOST_TUns32)cBnds.getHeight()) != height+s_sizeRectSize)) { ::SizeWindow(m_windowRef, width, height+s_sizeRectSize, true); } #else //GHOST_DRAW_CARBON_GUTTER if ((((GHOST_TUns32)cBnds.getWidth()) != width) || (((GHOST_TUns32)cBnds.getHeight()) != height)) { ::SizeWindow(m_windowRef, width, height, true); } #endif //GHOST_DRAW_CARBON_GUTTER return GHOST_kSuccess; } GHOST_TWindowState GHOST_WindowCocoa::getState() const { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getState(): window invalid") GHOST_TWindowState state; if (::IsWindowVisible(m_windowRef) == false) { state = GHOST_kWindowStateMinimized; } else if (::IsWindowInStandardState(m_windowRef, nil, nil)) { state = GHOST_kWindowStateMaximized; } else { state = GHOST_kWindowStateNormal; } return state; } void GHOST_WindowCocoa::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::screenToClient(): window invalid") Point point; point.h = inX; point.v = inY; GrafPtr oldPort; ::GetPort(&oldPort); ::SetPort(m_grafPtr); ::GlobalToLocal(&point); ::SetPort(oldPort); outX = point.h; outY = point.v; } void GHOST_WindowCocoa::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::clientToScreen(): window invalid") Point point; point.h = inX; point.v = inY; GrafPtr oldPort; ::GetPort(&oldPort); ::SetPort(m_grafPtr); ::LocalToGlobal(&point); ::SetPort(oldPort); outX = point.h; outY = point.v; } GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state) { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setState(): window invalid") switch (state) { case GHOST_kWindowStateMinimized: ::HideWindow(m_windowRef); break; case GHOST_kWindowStateModified: SetWindowModified(m_windowRef, 1); break; case GHOST_kWindowStateUnModified: SetWindowModified(m_windowRef, 0); break; case GHOST_kWindowStateMaximized: case GHOST_kWindowStateNormal: default: ::ShowWindow(m_windowRef); break; } return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order) { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setOrder(): window invalid") if (order == GHOST_kWindowOrderTop) { //::BringToFront(m_windowRef); is wrong, front window should be active for input too ::SelectWindow(m_windowRef); } else { /* doesnt work if you do this with a mouseclick */ ::SendBehind(m_windowRef, nil); } return GHOST_kSuccess; } /*#define WAIT_FOR_VSYNC 1*/ #ifdef WAIT_FOR_VSYNC #include #endif GHOST_TSuccess GHOST_WindowCocoa::swapBuffers() { #ifdef WAIT_FOR_VSYNC /* wait for vsync, to avoid tearing artifacts */ long VBL = 1; CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &VBL); #endif GHOST_TSuccess succeeded = GHOST_kSuccess; if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { if (m_aglCtx) { ::aglSwapBuffers(m_aglCtx); } else { succeeded = GHOST_kFailure; } } return succeeded; } GHOST_TSuccess GHOST_WindowCocoa::updateDrawingContext() { GHOST_TSuccess succeeded = GHOST_kSuccess; if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { if (m_aglCtx) { ::aglUpdateContext(m_aglCtx); } else { succeeded = GHOST_kFailure; } } return succeeded; } GHOST_TSuccess GHOST_WindowCocoa::activateDrawingContext() { GHOST_TSuccess succeeded = GHOST_kSuccess; if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { if (m_aglCtx) { ::aglSetCurrentContext(m_aglCtx); #ifdef GHOST_DRAW_CARBON_GUTTER // Restrict drawing to non-gutter area ::aglEnable(m_aglCtx, AGL_BUFFER_RECT); GHOST_Rect bnds; getClientBounds(bnds); GLint b[4] = { bnds.m_l, bnds.m_t+s_sizeRectSize, bnds.m_r-bnds.m_l, bnds.m_b-bnds.m_t }; GLboolean result = ::aglSetInteger(m_aglCtx, AGL_BUFFER_RECT, b); #endif //GHOST_DRAW_CARBON_GUTTER } else { succeeded = GHOST_kFailure; } } return succeeded; } GHOST_TSuccess GHOST_WindowCocoa::installDrawingContext(GHOST_TDrawingContextType type) { GHOST_TSuccess success = GHOST_kFailure; switch (type) { case GHOST_kDrawingContextTypeOpenGL: { if (!getValid()) break; AGLPixelFormat pixelFormat; if (!m_fullScreen) { pixelFormat = ::aglChoosePixelFormat(0, 0, sPreferredFormatWindow); m_aglCtx = ::aglCreateContext(pixelFormat, s_firstaglCtx); if (!m_aglCtx) break; if (!s_firstaglCtx) s_firstaglCtx = m_aglCtx; success = ::aglSetDrawable(m_aglCtx, m_grafPtr) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure; } else { //GHOST_PRINT("GHOST_WindowCocoa::installDrawingContext(): init full-screen OpenGL\n"); GDHandle device=::GetMainDevice();pixelFormat=::aglChoosePixelFormat(&device,1,sPreferredFormatFullScreen); m_aglCtx = ::aglCreateContext(pixelFormat, 0); if (!m_aglCtx) break; if (!s_firstaglCtx) s_firstaglCtx = m_aglCtx; //GHOST_PRINT("GHOST_WindowCocoa::installDrawingContext(): created OpenGL context\n"); //::CGGetActiveDisplayList(0, NULL, &m_numDisplays) success = ::aglSetFullScreen(m_aglCtx, m_fullScreenWidth, m_fullScreenHeight, 75, 0) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure; /* if (success == GHOST_kSuccess) { GHOST_PRINT("GHOST_WindowCocoa::installDrawingContext(): init full-screen OpenGL succeeded\n"); } else { GHOST_PRINT("GHOST_WindowCocoa::installDrawingContext(): init full-screen OpenGL failed\n"); } */ } ::aglDestroyPixelFormat(pixelFormat); } break; case GHOST_kDrawingContextTypeNone: success = GHOST_kSuccess; break; default: break; } return success; } GHOST_TSuccess GHOST_WindowCocoa::removeDrawingContext() { GHOST_TSuccess success = GHOST_kFailure; switch (m_drawingContextType) { case GHOST_kDrawingContextTypeOpenGL: if (m_aglCtx) { aglSetCurrentContext(NULL); aglSetDrawable(m_aglCtx, NULL); //aglDestroyContext(m_aglCtx); if (s_firstaglCtx == m_aglCtx) s_firstaglCtx = NULL; success = ::aglDestroyContext(m_aglCtx) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure; m_aglCtx = 0; } break; case GHOST_kDrawingContextTypeNone: success = GHOST_kSuccess; break; default: break; } return success; } GHOST_TSuccess GHOST_WindowCocoa::invalidate() { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::invalidate(): window invalid") if (!m_fullScreen) { Rect rect; ::GetPortBounds(m_grafPtr, &rect); ::InvalWindowRect(m_windowRef, &rect); } else { //EventRef event; //OSStatus status = ::CreateEvent(NULL, kEventClassWindow, kEventWindowUpdate, 0, 0, &event); //GHOST_PRINT("GHOST_WindowCocoa::invalidate(): created event " << status << " \n"); //status = ::SetEventParameter(event, kEventParamDirectObject, typeWindowRef, sizeof(WindowRef), this); //GHOST_PRINT("GHOST_WindowCocoa::invalidate(): set event parameter " << status << " \n"); //status = ::PostEventToQueue(::GetMainEventQueue(), event, kEventPriorityStandard); //status = ::SendEventToEventTarget(event, ::GetApplicationEventTarget()); //GHOST_PRINT("GHOST_WindowCocoa::invalidate(): added event to queue " << status << " \n"); m_fullScreenDirty = true; } return GHOST_kSuccess; } void GHOST_WindowCocoa::gen2mac(const STR_String& in, Str255 out) const { STR_String tempStr = in; int num = tempStr.Length(); if (num > 255) num = 255; ::memcpy(out+1, tempStr.Ptr(), num); out[0] = num; } void GHOST_WindowCocoa::mac2gen(const Str255 in, STR_String& out) const { char tmp[256]; ::memcpy(tmp, in+1, in[0]); tmp[in[0]] = '\0'; out = tmp; } void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) const { static bool systemCursorVisible = true; if (visible != systemCursorVisible) { if (visible) { ::ShowCursor(); systemCursorVisible = true; } else { ::HideCursor(); systemCursorVisible = false; } } if (cursor == GHOST_kStandardCursorCustom && m_customCursor) { ::SetCursor( m_customCursor ); } else { int carbon_cursor; #define GCMAP(ghostCursor, carbonCursor) case ghostCursor: carbon_cursor = carbonCursor; break switch (cursor) { default: GCMAP( GHOST_kStandardCursorDefault, kThemeArrowCursor); GCMAP( GHOST_kStandardCursorRightArrow, kThemeAliasArrowCursor); GCMAP( GHOST_kStandardCursorLeftArrow, kThemeArrowCursor); GCMAP( GHOST_kStandardCursorInfo, kThemeArrowCursor); GCMAP( GHOST_kStandardCursorDestroy, kThemeArrowCursor); GCMAP( GHOST_kStandardCursorHelp, kThemeArrowCursor); GCMAP( GHOST_kStandardCursorCycle, kThemeArrowCursor); GCMAP( GHOST_kStandardCursorSpray, kThemeArrowCursor); GCMAP( GHOST_kStandardCursorWait, kThemeWatchCursor); GCMAP( GHOST_kStandardCursorText, kThemeIBeamCursor); GCMAP( GHOST_kStandardCursorCrosshair, kThemeCrossCursor); GCMAP( GHOST_kStandardCursorUpDown, kThemeClosedHandCursor); GCMAP( GHOST_kStandardCursorLeftRight, kThemeClosedHandCursor); GCMAP( GHOST_kStandardCursorTopSide, kThemeArrowCursor); GCMAP( GHOST_kStandardCursorBottomSide, kThemeArrowCursor); GCMAP( GHOST_kStandardCursorLeftSide, kThemeResizeLeftCursor); GCMAP( GHOST_kStandardCursorRightSide, kThemeResizeRightCursor); GCMAP( GHOST_kStandardCursorTopLeftCorner, kThemeArrowCursor); GCMAP( GHOST_kStandardCursorTopRightCorner, kThemeArrowCursor); GCMAP( GHOST_kStandardCursorBottomRightCorner, kThemeArrowCursor); GCMAP( GHOST_kStandardCursorBottomLeftCorner, kThemeArrowCursor); }; #undef GCMAP ::SetThemeCursor(carbon_cursor); } } bool GHOST_WindowCocoa::getFullScreenDirty() { return m_fullScreen && m_fullScreenDirty; } GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible) { if (::FrontWindow() == m_windowRef) { loadCursor(visible, getCursorShape()); } return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape) { if (m_customCursor) { delete m_customCursor; m_customCursor = 0; } if (::FrontWindow() == m_windowRef) { loadCursor(getCursorVisibility(), shape); } return GHOST_kSuccess; } #if 0 /** Reverse the bits in a GHOST_TUns8 */ static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch) { ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA); ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC); ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0); return ch; } #endif /** Reverse the bits in a GHOST_TUns16 */ static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt) { shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA); shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC); shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0); shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00); return shrt; } GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color) { int y; if (m_customCursor) { delete m_customCursor; m_customCursor = 0; } m_customCursor = new Cursor; if (!m_customCursor) return GHOST_kFailure; for (y=0; y<16; y++) { #if !defined(__LITTLE_ENDIAN__) m_customCursor->data[y] = uns16ReverseBits((bitmap[2*y]<<0) | (bitmap[2*y+1]<<8)); m_customCursor->mask[y] = uns16ReverseBits((mask[2*y]<<0) | (mask[2*y+1]<<8)); #else m_customCursor->data[y] = uns16ReverseBits((bitmap[2*y+1]<<0) | (bitmap[2*y]<<8)); m_customCursor->mask[y] = uns16ReverseBits((mask[2*y+1]<<0) | (mask[2*y]<<8)); #endif } m_customCursor->hotSpot.h = hotX; m_customCursor->hotSpot.v = hotY; if (::FrontWindow() == m_windowRef) { loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom); } return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], int hotX, int hotY) { return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*) mask, 16, 16, hotX, hotY, 0, 1); } void GHOST_WindowCocoa::setMac_windowState(short value) { mac_windowState = value; } short GHOST_WindowCocoa::getMac_windowState() { return mac_windowState; }