X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/fe686e5a1f80c9ba22a622e96251c054da0366c1..78eecde0860f23a11932c53b1e59e41a6effd6bb:/src/cocoa/cursor.mm diff --git a/src/cocoa/cursor.mm b/src/cocoa/cursor.mm index 502ec33cec..c0458ce439 100644 --- a/src/cocoa/cursor.mm +++ b/src/cocoa/cursor.mm @@ -17,11 +17,13 @@ #ifndef WX_PRECOMP #include "wx/icon.h" + #include "wx/log.h" #endif //WX_PRECOMP #import #import #include "wx/cocoa/string.h" +#include "wx/cocoa/autorelease.h" IMPLEMENT_DYNAMIC_CLASS(wxCursor, wxBitmap) @@ -182,15 +184,12 @@ ClassicCursor gMacCursors[kwxCursorLast+1] = // End of data copied from src/mac/carbon/cursor.cpp /////////////////////////////////////////////////////////////////////////// -/* wxStockCursor +/* NSCursorCreateWithPrivateId * Returns a newly allocated (i.e. retainCount == 1) NSCursor based on the * classic Mac OS cursor data in this source file. This allows us to * implement the "stock" wxWidgets cursors which aren't present in Cocoa. - * FIXME: This function should be static. - * FIXME: This function should use "Alloc" in preference to "Get" to follow - * the proper Cocoa naming conventions. */ -NSCursor* wxGetStockCursor( short sIndex ) +static inline NSCursor* NSCursorCreateWithPrivateId(short sIndex) { ClassicCursor* pCursor = &gMacCursors[sIndex]; @@ -309,132 +308,151 @@ wxCursor::wxCursor(const wxString& cursor_file, long flags, int hotSpotX, int ho [theImage release]; } -// Cursors by stock number -wxCursor::wxCursor(int cursor_type) -{ - m_refData = new wxCursorRefData; - - switch (cursor_type) - { - case wxCURSOR_IBEAM: - M_CURSORDATA->m_hCursor = [[NSCursor IBeamCursor] retain]; - break; - case wxCURSOR_ARROW: - M_CURSORDATA->m_hCursor = [[NSCursor arrowCursor] retain]; - break; -/* TODO: - case wxCURSOR_COPY_ARROW: - M_CURSORDATA->m_themeCursor = kThemeCopyArrowCursor ; - break; - case wxCURSOR_WAIT: - M_CURSORDATA->m_themeCursor = kThemeWatchCursor ; - break; - case wxCURSOR_CROSS: - M_CURSORDATA->m_themeCursor = kThemeCrossCursor; - break; - case wxCURSOR_SIZENWSE: - { - M_CURSORDATA->m_hCursor = wxGetStockCursor(kwxCursorSizeNWSE); - } - break; -*/ - case wxCURSOR_SIZENESW: - { - M_CURSORDATA->m_hCursor = wxGetStockCursor(kwxCursorSizeNESW); - } - break; -/* TODO: - case wxCURSOR_SIZEWE: - { - M_CURSORDATA->m_themeCursor = kThemeResizeLeftRightCursor; - } - break; -*/ - case wxCURSOR_SIZENS: - { - M_CURSORDATA->m_hCursor = wxGetStockCursor(kwxCursorSizeNS); - } - break; - case wxCURSOR_SIZING: - { - M_CURSORDATA->m_hCursor = wxGetStockCursor(kwxCursorSize); - } - break; -/* TODO: - case wxCURSOR_HAND: - { - M_CURSORDATA->m_themeCursor = kThemePointingHandCursor; - } - break; -*/ - case wxCURSOR_BULLSEYE: - { - M_CURSORDATA->m_hCursor = wxGetStockCursor(kwxCursorBullseye); - } - break; - case wxCURSOR_PENCIL: - { - M_CURSORDATA->m_hCursor = wxGetStockCursor(kwxCursorPencil); - } - break; - case wxCURSOR_MAGNIFIER: - { - M_CURSORDATA->m_hCursor = wxGetStockCursor(kwxCursorMagnifier); - } - break; - case wxCURSOR_NO_ENTRY: - { - M_CURSORDATA->m_hCursor = wxGetStockCursor(kwxCursorNoEntry); - } - break; -/* TODO: - case wxCURSOR_WATCH: - { - M_CURSORDATA->m_themeCursor = kThemeWatchCursor; - break; - } -*/ - case wxCURSOR_PAINT_BRUSH: - { - M_CURSORDATA->m_hCursor = wxGetStockCursor(kwxCursorPaintBrush); - break; - } - case wxCURSOR_POINT_LEFT: - { - M_CURSORDATA->m_hCursor = wxGetStockCursor(kwxCursorPointLeft); - break; - } - case wxCURSOR_POINT_RIGHT: - { - M_CURSORDATA->m_hCursor = wxGetStockCursor(kwxCursorPointRight); - break; - } - case wxCURSOR_QUESTION_ARROW: - { - M_CURSORDATA->m_hCursor = wxGetStockCursor(kwxCursorQuestionArrow); - break; - } - case wxCURSOR_BLANK: - { - M_CURSORDATA->m_hCursor = wxGetStockCursor(kwxCursorBlank); - break; - } - case wxCURSOR_RIGHT_ARROW: - { - M_CURSORDATA->m_hCursor = wxGetStockCursor(kwxCursorRightArrow); - break; - } - case wxCURSOR_SPRAYCAN: +// Returns a system cursor given the NSCursor class method selector or +// nil if NSCursor does not respond to the message. +// For example, OS X before 10.3 won't respond to pointingHandCursor. +static inline NSCursor* GetSystemCursorWithSelector(SEL cursorSelector) +{ + if([NSCursor respondsToSelector: cursorSelector]) + return [NSCursor performSelector: cursorSelector]; + else + return nil; +} + +// Please maintain order as if this were an array keyed on wxStockCursor +static inline SEL GetCursorSelectorForStockCursor(int stock_cursor_id) +{ + switch(stock_cursor_id) + { + case wxCURSOR_ARROW: return @selector(arrowCursor); + case wxCURSOR_RIGHT_ARROW: break; + case wxCURSOR_BULLSEYE: break; + case wxCURSOR_CHAR: break; + case wxCURSOR_CROSS: return @selector(crosshairCursor); + case wxCURSOR_HAND: return @selector(pointingHandCursor); + case wxCURSOR_IBEAM: return @selector(IBeamCursor); + case wxCURSOR_LEFT_BUTTON: break; + case wxCURSOR_MAGNIFIER: break; + case wxCURSOR_MIDDLE_BUTTON: break; + case wxCURSOR_NO_ENTRY: break; + case wxCURSOR_PAINT_BRUSH: break; + case wxCURSOR_PENCIL: break; + case wxCURSOR_POINT_LEFT: break; + case wxCURSOR_POINT_RIGHT: break; + case wxCURSOR_QUESTION_ARROW: break; + case wxCURSOR_RIGHT_BUTTON: break; + case wxCURSOR_SIZENESW: break; + case wxCURSOR_SIZENS: return @selector(resizeUpDownCursor); + case wxCURSOR_SIZENWSE: break; + case wxCURSOR_SIZEWE: return @selector(resizeLeftRightCursor); + case wxCURSOR_SIZING: break; + case wxCURSOR_SPRAYCAN: break; + case wxCURSOR_WAIT: break; + case wxCURSOR_WATCH: break; + case wxCURSOR_BLANK: break; + case wxCURSOR_ARROWWAIT: break; + default: break; + } + return NULL; +} + +// Please maintain order as if this were an array keyed on wxStockCursor +static inline int GetPrivateCursorIdForStockCursor(int stock_cursor_id) +{ + switch(stock_cursor_id) + { + case wxCURSOR_ARROW: break; // NSCursor + case wxCURSOR_RIGHT_ARROW: return kwxCursorRightArrow; + case wxCURSOR_BULLSEYE: return kwxCursorBullseye; + case wxCURSOR_CHAR: break; + case wxCURSOR_CROSS: break; // NSCursor + case wxCURSOR_HAND: break; // NSCursor (OS X >= 10.3) + case wxCURSOR_IBEAM: break; // NSCursor + case wxCURSOR_LEFT_BUTTON: break; + case wxCURSOR_MAGNIFIER: return kwxCursorMagnifier; + case wxCURSOR_MIDDLE_BUTTON: break; + case wxCURSOR_NO_ENTRY: return kwxCursorNoEntry; + case wxCURSOR_PAINT_BRUSH: return kwxCursorPaintBrush; + case wxCURSOR_PENCIL: return kwxCursorPencil; + case wxCURSOR_POINT_LEFT: return kwxCursorPointLeft; + case wxCURSOR_POINT_RIGHT: return kwxCursorPointRight; + case wxCURSOR_QUESTION_ARROW: return kwxCursorQuestionArrow; + case wxCURSOR_RIGHT_BUTTON: break; + case wxCURSOR_SIZENESW: return kwxCursorSizeNESW; + case wxCURSOR_SIZENS: return kwxCursorSizeNS; // also NSCursor + case wxCURSOR_SIZENWSE: return kwxCursorSizeNWSE; + case wxCURSOR_SIZEWE: break; // NSCursor + case wxCURSOR_SIZING: return kwxCursorSize; + case wxCURSOR_SPRAYCAN: return kwxCursorRoller; + case wxCURSOR_WAIT: break; + case wxCURSOR_WATCH: break; + case wxCURSOR_BLANK: return kwxCursorBlank; + case wxCURSOR_ARROWWAIT: break; + default: break; + } + return -1; +} + +// Keep an array of stock cursors so they can share wxCursorRefData and thus +// wxObject::IsSameAs will return true. +// They will obviously be destroyed at static destruction time which should +// theoretically be fine. +static wxCursor s_stockCursors[wxCURSOR_MAX]; + +// Cursors by stock number (enum wxStockCursor) +wxCursor::wxCursor(int stock_cursor_id) +{ + // We default-constructed wxObject so our m_refData == NULL + if(stock_cursor_id >= 0 && stock_cursor_id < wxCURSOR_MAX) + { + // Attempt to reference an existing stock cursor + Ref(s_stockCursors[stock_cursor_id]); + } + // If we succeeded in getting an existing stock cursor, we're done. + if(m_refData != NULL) + return; + + m_refData = new wxCursorRefData; + + M_CURSORDATA->m_hCursor = nil; + + wxCHECK_RET( stock_cursor_id > wxCURSOR_NONE && stock_cursor_id < wxCURSOR_MAX, + wxT("invalid cursor id in wxCursor() ctor") ); + + // Stage 1: Try a system cursor + SEL cursorSelector; + if( (cursorSelector = GetCursorSelectorForStockCursor(stock_cursor_id)) != NULL) + { + M_CURSORDATA->m_hCursor = [GetSystemCursorWithSelector(cursorSelector) retain]; + } + + // TODO: Provide a pointing hand for OS X < 10.3 if desired + + // Stage 2: Try one of the 'CURS'-style cursors + if(M_CURSORDATA->m_hCursor == nil) + { + int privateId; + if( (privateId = GetPrivateCursorIdForStockCursor(stock_cursor_id)) >= 0) { - M_CURSORDATA->m_hCursor = wxGetStockCursor(kwxCursorRoller); - break; + M_CURSORDATA->m_hCursor = NSCursorCreateWithPrivateId(privateId); } - case wxCURSOR_CHAR: - case wxCURSOR_LEFT_BUTTON: - case wxCURSOR_RIGHT_BUTTON: - case wxCURSOR_MIDDLE_BUTTON: - default: - break; + } + + // Stage 3: Give up, complain, and use a normal arrow + if(M_CURSORDATA->m_hCursor == nil) + { + wxLogDebug(wxT("Could not find suitable cursor for wxStockCursor = %d. Using normal pointer."), stock_cursor_id); + M_CURSORDATA->m_hCursor = [[NSCursor arrowCursor] retain]; + } + + // This should never happen as the arrowCursor should always exist. + wxASSERT(M_CURSORDATA->m_hCursor != nil); + + // Store ourself as the new stock cursor for this ID so that future + // calls will share the same ref data. + if(stock_cursor_id >= 0 && stock_cursor_id < wxCURSOR_MAX) + { + s_stockCursors[stock_cursor_id] = *this; } }