1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/mac/classic/cursor.cpp 
   3 // Purpose:     wxCursor class 
   4 // Author:      Stefan Csomor 
   8 // Copyright:   (c) Stefan Csomor 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 #include "wx/wxprec.h" 
  18 #include "wx/cursor.h" 
  26 #include "wx/xpmdecod.h" 
  28 #include "wx/mac/private.h" 
  30 IMPLEMENT_DYNAMIC_CLASS(wxCursor
, wxBitmap
) 
  32 const short kwxCursorBullseye 
= 10 ; 
  33 const short kwxCursorBlank 
= 11 ; 
  34 const short kwxCursorPencil 
= 12 ; 
  35 const short kwxCursorMagnifier 
= 13 ; 
  36 const short kwxCursorNoEntry 
= 14 ; 
  37 const short kwxCursorPaintBrush 
= 15 ; 
  38 const short kwxCursorPointRight 
= 16 ; 
  39 const short kwxCursorPointLeft 
= 17 ; 
  40 const short kwxCursorQuestionArrow 
= 18 ; 
  41 const short kwxCursorRightArrow 
= 19 ; 
  42 const short kwxCursorSizeNS 
= 20 ; 
  43 const short kwxCursorSize 
= 21 ; 
  44 const short kwxCursorSizeNESW 
= 22 ; 
  45 const short kwxCursorSizeNWSE 
= 23 ; 
  46 const short kwxCursorRoller 
= 24 ; 
  48 wxCursor    gMacCurrentCursor 
; 
  50 wxCursorRefData::wxCursorRefData() 
  55     m_disposeHandle 
= false ; 
  56     m_releaseHandle 
= false ; 
  57     m_isColorCursor 
= false ; 
  61 wxCursorRefData::~wxCursorRefData() 
  63     if ( m_isColorCursor 
) 
  65         ::DisposeCCursor( (CCrsrHandle
) m_hCursor 
) ; 
  67     else if ( m_disposeHandle 
) 
  69         ::DisposeHandle( (Handle 
) m_hCursor 
) ; 
  71     else if ( m_releaseHandle 
) 
  73         // we don't release the resource since it may already 
  83 wxCursor::wxCursor(const char WXUNUSED(bits
)[], int WXUNUSED(width
), int WXUNUSED(height
), 
  84     int WXUNUSED(hotSpotX
), int WXUNUSED(hotSpotY
), const char WXUNUSED(maskBits
)[]) 
  88 wxCursor::wxCursor( const wxImage 
&image 
) 
  90     CreateFromImage( image 
) ; 
  93 wxCursor::wxCursor(const char **bits
) 
  95     (void) CreateFromXpm(bits
); 
  98 wxCursor::wxCursor(char **bits
) 
 100     (void) CreateFromXpm((const char **)bits
); 
 103 bool wxCursor::CreateFromXpm(const char **bits
) 
 105     wxCHECK_MSG( bits 
!= NULL
, false, wxT("invalid cursor data") ); 
 106     wxXPMDecoder decoder
; 
 107     wxImage img 
= decoder
.ReadData(bits
); 
 108     wxCHECK_MSG( img
.Ok(), false, wxT("invalid cursor data") ); 
 109     CreateFromImage( img 
) ; 
 113 short GetCTabIndex( CTabHandle colors 
, RGBColor 
*col 
) 
 116     unsigned long bestdiff 
= 0xFFFF ; 
 117     for ( int i 
= 0 ; i 
< (**colors
).ctSize 
; ++i 
) 
 119         unsigned long diff 
= abs(col
->red 
-  (**colors
).ctTable
[i
].rgb
.red 
) + 
 120             abs(col
->green 
-  (**colors
).ctTable
[i
].rgb
.green 
) + 
 121             abs(col
->blue 
-  (**colors
).ctTable
[i
].rgb
.blue 
) ; 
 122         if ( diff 
< bestdiff 
) 
 125             retval 
= (**colors
).ctTable
[i
].value 
; 
 131 void wxCursor::CreateFromImage(const wxImage 
& image
) 
 133     m_refData 
= new wxCursorRefData
; 
 138     int hotSpotX 
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
); 
 139     int hotSpotY 
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
); 
 140     int image_w 
= image
.GetWidth(); 
 141     int image_h 
= image
.GetHeight(); 
 143     wxASSERT_MSG( hotSpotX 
>= 0 && hotSpotX 
< image_w 
&& 
 144                   hotSpotY 
>= 0 && hotSpotY 
< image_h
, 
 145                   _T("invalid cursor hot spot coordinates") ); 
 147     wxImage 
image16(image
); // final image of correct size 
 149     // if image is too small then place it in the center, resize it if too big 
 150     if ((w 
> image_w
) && (h 
> image_h
)) 
 152         wxPoint 
offset((w 
- image_w
)/2, (h 
- image_h
)/2); 
 153         hotSpotX 
= hotSpotX 
+ offset
.x
; 
 154         hotSpotY 
= hotSpotY 
+ offset
.y
; 
 156         image16 
= image
.Size(wxSize(w
, h
), offset
); 
 158     else if ((w 
!= image_w
) || (h 
!= image_h
)) 
 160         hotSpotX 
= int(hotSpotX 
* double(w
) / double(image_w
)); 
 161         hotSpotY 
= int(hotSpotY 
* double(h
) / double(image_h
)); 
 163         image16 
= image
.Scale(w
, h
); 
 166     unsigned char * rgbBits 
= image16
.GetData(); 
 167     bool bHasMask 
= image16
.HasMask() ; 
 170     // monochrome implementation 
 171     M_CURSORDATA
->m_hCursor 
= NewHandle( sizeof( Cursor 
) ) ; 
 172     M_CURSORDATA
->m_disposeHandle 
= true ; 
 173     HLock( (Handle
) M_CURSORDATA
->m_hCursor 
) ; 
 174     CursPtr cp 
= *(CursHandle
)M_CURSORDATA
->m_hCursor 
; 
 175     memset( cp
->data 
, 0 , sizeof( Bits16 
) ) ; 
 176     memset( cp
->mask 
, 0 , sizeof( Bits16 
) ) ; 
 178     unsigned char mr 
= image16
.GetMaskRed() ; 
 179     unsigned char mg 
= image16
.GetMaskGreen() ; 
 180     unsigned char mb 
= image16
.GetMaskBlue() ; 
 181     for ( int y 
= 0 ; y 
< h 
; ++y 
) 
 186         for ( int x 
= 0 ; x 
< w 
; ++x 
) 
 188             long pos 
= (y 
* w 
+ x
) * 3; 
 190             unsigned char r 
= rgbBits
[pos
] ; 
 191             unsigned char g 
= rgbBits
[pos
+1] ; 
 192             unsigned char b 
= rgbBits
[pos
+2] ; 
 193             if ( bHasMask 
&& r
==mr 
&& g
==mg 
&& b
==mb 
) 
 195                 // masked area, does not appear anywhere 
 199                 if ( (int)r 
+ (int)g 
+ (int)b 
< 0x0200 ) 
 201                     rowbits 
|= ( 1 << (15-x
) ) ; 
 203                 maskbits 
|= ( 1 << (15-x
) ) ; 
 206         cp
->data
[y
] = rowbits 
; 
 207         cp
->mask
[y
] = maskbits 
; 
 211         memcpy( cp
->mask 
, cp
->data 
, sizeof( Bits16
) ) ; 
 213     cp
->hotSpot
.h 
= hotSpotX 
; 
 214     cp
->hotSpot
.v 
= hotSpotY 
; 
 215     HUnlock( (Handle
) M_CURSORDATA
->m_hCursor 
) ; 
 217     PixMapHandle pm 
= (PixMapHandle
) NewHandleClear( sizeof (PixMap
))  ; 
 219     short bytesPerPixel 
= 1 ; 
 221     Rect bounds 
= { 0 , 0 , extent 
, extent 
} ; 
 222     CCrsrHandle ch 
= (CCrsrHandle
) NewHandleClear ( sizeof( CCrsr 
) ) ; 
 223     CTabHandle newColors 
= GetCTable( 8 ) ; 
 224     HandToHand((Handle 
*) &newColors
); 
 225     // set the values to the indices 
 226     for ( int i 
= 0 ; i 
< (**newColors
).ctSize 
; ++i 
) 
 228         (**newColors
).ctTable
[i
].value 
= i 
; 
 230     HLock( (Handle
) ch
) ; 
 231     (**ch
).crsrType 
= 0x8001 ; // color cursors 
 232     (**ch
).crsrMap 
= pm 
; 
 233     short bytesPerRow 
= bytesPerPixel 
* extent 
; 
 236     (**pm
).rowBytes 
= bytesPerRow 
| 0x8000; 
 237     (**pm
).bounds 
= bounds
; 
 238     (**pm
).pmVersion 
= 0; 
 241     (**pm
).hRes 
= 0x00480000; /* 72 DPI default res */ 
 242     (**pm
).vRes 
= 0x00480000; /* 72 DPI default res */ 
 243     (**pm
).pixelSize 
= depth
; 
 244     (**pm
).pixelType 
= 0; 
 246     (**pm
).cmpSize 
= depth
; 
 247     (**pm
).pmTable 
= newColors
; 
 249     (**ch
).crsrData 
= NewHandleClear( extent 
* bytesPerRow 
) ; 
 250     (**ch
).crsrXData 
= NULL 
; 
 251     (**ch
).crsrXValid 
= 0; 
 252     (**ch
).crsrXHandle 
= NULL
; 
 254     (**ch
).crsrHotSpot
.h 
= hotSpotX 
; 
 255     (**ch
).crsrHotSpot
.v 
= hotSpotY 
; 
 256     (**ch
).crsrXTable 
= NULL 
; 
 257     (**ch
).crsrID 
= GetCTSeed() ; 
 259     memset( (**ch
).crsr1Data  
, 0 , sizeof( Bits16 
) ) ; 
 260     memset( (**ch
).crsrMask 
, 0 , sizeof( Bits16 
) ) ; 
 262     unsigned char mr 
= image16
.GetMaskRed() ; 
 263     unsigned char mg 
= image16
.GetMaskGreen() ; 
 264     unsigned char mb 
= image16
.GetMaskBlue() ; 
 265     for ( int y 
= 0 ; y 
< h 
; ++y 
) 
 270         for ( int x 
= 0 ; x 
< w 
; ++x 
) 
 272             long pos 
= (y 
* w 
+ x
) * 3; 
 274             unsigned char r 
= rgbBits
[pos
] ; 
 275             unsigned char g 
= rgbBits
[pos
+1] ; 
 276             unsigned char b 
= rgbBits
[pos
+2] ; 
 277             RGBColor col 
= { 0xFFFF ,0xFFFF, 0xFFFF } ; 
 279             if ( bHasMask 
&& r
==mr 
&& g
==mg 
&& b
==mb 
) 
 281                 // masked area, does not appear anywhere 
 285                 if ( (int)r 
+ (int)g 
+ (int)b 
< 0x0200 ) 
 287                     rowbits 
|= ( 1 << (15-x
) ) ; 
 289                 maskbits 
|= ( 1 << (15-x
) ) ; 
 291                 col 
= *((RGBColor
*) wxColor( r 
, g 
, b 
).GetPixel()) ; 
 293             *((*(**ch
).crsrData
) + y 
* bytesPerRow 
+ x
) = 
 294                 GetCTabIndex( newColors 
, &col
) ; 
 296         (**ch
).crsr1Data
[y
] = rowbits 
; 
 297         (**ch
).crsrMask
[y
] = maskbits 
; 
 301         memcpy( (**ch
).crsrMask 
, (**ch
).crsr1Data 
, sizeof( Bits16
) ) ; 
 304     HUnlock((Handle
) ch
) ; 
 305     M_CURSORDATA
->m_hCursor 
= ch 
; 
 306     M_CURSORDATA
->m_isColorCursor 
= true ; 
 310 wxCursor::wxCursor(const wxString
& cursor_file
, long flags
, int hotSpotX
, int hotSpotY
) 
 312     m_refData 
= new wxCursorRefData
; 
 313     if ( flags 
== wxBITMAP_TYPE_MACCURSOR_RESOURCE 
) 
 316         wxMacStringToPascal( cursor_file 
, theName 
) ; 
 318         wxStAppResource resload 
; 
 319         Handle resHandle 
= ::GetNamedResource( 'crsr' , theName 
) ; 
 324             GetResInfo( resHandle 
, &theId 
, &theType 
, theName 
) ; 
 325             ReleaseResource( resHandle 
) ; 
 326             M_CURSORDATA
->m_hCursor 
= GetCCursor( theId 
) ; 
 327             if ( M_CURSORDATA
->m_hCursor 
) 
 328                 M_CURSORDATA
->m_isColorCursor 
= true ; 
 332             Handle resHandle 
= ::GetNamedResource( 'CURS' , theName 
) ; 
 337                 GetResInfo( resHandle 
, &theId 
, &theType 
, theName 
) ; 
 338                 ReleaseResource( resHandle 
) ; 
 339                  M_CURSORDATA
->m_hCursor 
= GetCursor( theId 
) ; 
 340                 if ( M_CURSORDATA
->m_hCursor 
) 
 341                     M_CURSORDATA
->m_releaseHandle 
= true ; 
 348         image
.LoadFile( cursor_file 
, flags 
) ; 
 351             image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
,hotSpotX 
) ; 
 352             image
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
,hotSpotY 
) ; 
 354             CreateFromImage(image
) ; 
 359 // Cursors by stock number 
 360 wxCursor::wxCursor(int cursor_type
) 
 362     m_refData 
= new wxCursorRefData
; 
 366     case wxCURSOR_COPY_ARROW
: 
 367         M_CURSORDATA
->m_themeCursor 
= kThemeCopyArrowCursor 
; 
 370         M_CURSORDATA
->m_themeCursor 
= kThemeWatchCursor 
; 
 373         M_CURSORDATA
->m_themeCursor 
= kThemeIBeamCursor 
; 
 376         M_CURSORDATA
->m_themeCursor 
= kThemeCrossCursor
; 
 378     case wxCURSOR_SIZENWSE
: 
 380             wxStAppResource resload 
; 
 381             M_CURSORDATA
->m_hCursor 
= ::GetCursor(kwxCursorSizeNWSE
); 
 384     case wxCURSOR_SIZENESW
: 
 386             wxStAppResource resload 
; 
 387             M_CURSORDATA
->m_hCursor 
= ::GetCursor(kwxCursorSizeNESW
); 
 390     case wxCURSOR_SIZEWE
: 
 392             M_CURSORDATA
->m_themeCursor 
= kThemeResizeLeftRightCursor
; 
 395     case wxCURSOR_SIZENS
: 
 397             wxStAppResource resload 
; 
 398             M_CURSORDATA
->m_hCursor 
= ::GetCursor(kwxCursorSizeNS
); 
 401     case wxCURSOR_SIZING
: 
 403             wxStAppResource resload 
; 
 404             M_CURSORDATA
->m_hCursor 
= ::GetCursor(kwxCursorSize
); 
 409             M_CURSORDATA
->m_themeCursor 
= kThemePointingHandCursor
; 
 412     case wxCURSOR_BULLSEYE
: 
 414             wxStAppResource resload 
; 
 415             M_CURSORDATA
->m_hCursor 
= ::GetCursor(kwxCursorBullseye
); 
 418     case wxCURSOR_PENCIL
: 
 420             wxStAppResource resload 
; 
 421             M_CURSORDATA
->m_hCursor 
= ::GetCursor(kwxCursorPencil
); 
 424     case wxCURSOR_MAGNIFIER
: 
 426             wxStAppResource resload 
; 
 427             M_CURSORDATA
->m_hCursor 
= ::GetCursor(kwxCursorMagnifier
); 
 430     case wxCURSOR_NO_ENTRY
: 
 432             wxStAppResource resload 
; 
 433             M_CURSORDATA
->m_hCursor 
= ::GetCursor(kwxCursorNoEntry
); 
 438             M_CURSORDATA
->m_themeCursor 
= kThemeWatchCursor
; 
 441     case wxCURSOR_PAINT_BRUSH
: 
 443             wxStAppResource resload 
; 
 444             M_CURSORDATA
->m_hCursor 
= ::GetCursor(kwxCursorPaintBrush
); 
 447     case wxCURSOR_POINT_LEFT
: 
 449             wxStAppResource resload 
; 
 450             M_CURSORDATA
->m_hCursor 
= ::GetCursor(kwxCursorPointLeft
); 
 453     case wxCURSOR_POINT_RIGHT
: 
 455             wxStAppResource resload 
; 
 456             M_CURSORDATA
->m_hCursor 
= ::GetCursor(kwxCursorPointRight
); 
 459     case wxCURSOR_QUESTION_ARROW
: 
 461             wxStAppResource resload 
; 
 462             M_CURSORDATA
->m_hCursor 
= ::GetCursor(kwxCursorQuestionArrow
); 
 467             wxStAppResource resload 
; 
 468             M_CURSORDATA
->m_hCursor 
= ::GetCursor(kwxCursorBlank
); 
 471     case wxCURSOR_RIGHT_ARROW
: 
 473             wxStAppResource resload 
; 
 474             M_CURSORDATA
->m_hCursor 
= ::GetCursor(kwxCursorRightArrow
); 
 477     case wxCURSOR_SPRAYCAN
: 
 479             wxStAppResource resload 
; 
 480             M_CURSORDATA
->m_hCursor 
= ::GetCursor(kwxCursorRoller
); 
 485     case wxCURSOR_LEFT_BUTTON
: 
 486     case wxCURSOR_RIGHT_BUTTON
: 
 487     case wxCURSOR_MIDDLE_BUTTON
: 
 489         M_CURSORDATA
->m_themeCursor 
= kThemeArrowCursor 
; 
 492     if ( M_CURSORDATA
->m_themeCursor 
== -1 ) 
 493         M_CURSORDATA
->m_releaseHandle 
= true ; 
 496 void wxCursor::MacInstall() const 
 498     gMacCurrentCursor 
= *this ; 
 499     if ( m_refData 
&& M_CURSORDATA
->m_themeCursor 
!= -1 ) 
 501         SetThemeCursor( M_CURSORDATA
->m_themeCursor 
) ; 
 503     else if ( m_refData 
&& M_CURSORDATA
->m_hCursor 
) 
 505         if ( M_CURSORDATA
->m_isColorCursor 
) 
 506             ::SetCCursor( (CCrsrHandle
) M_CURSORDATA
->m_hCursor 
) ; 
 508             ::SetCursor( * (CursHandle
) M_CURSORDATA
->m_hCursor 
) ; 
 512         SetThemeCursor( kThemeArrowCursor 
) ; 
 516 wxCursor::~wxCursor() 
 520 // Global cursor setting 
 521 void wxSetCursor(const wxCursor
& cursor
) 
 523     cursor
.MacInstall() ;