1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/cursor.cpp
3 // Purpose: wxCursor class
4 // Author: Julian Smart
8 // Copyright: (c) 1997-2003 Julian Smart and Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "cursor.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
35 #include "wx/bitmap.h"
37 #include "wx/cursor.h"
40 #include "wx/ptr_scpd.h"
42 #include "wx/module.h"
44 #include "wx/msw/private.h"
46 #ifndef __WXMICROWIN__
47 #include "wx/msw/dib.h"
50 #if wxUSE_RESOURCE_LOADING_IN_MSW
51 #include "wx/msw/curico.h"
52 #include "wx/msw/curicop.h"
55 // define functions missing in MicroWin
57 static inline void DestroyCursor(HCURSOR
) { }
58 static inline void SetCursor(HCURSOR
) { }
59 #endif // __WXMICROWIN__
61 // ----------------------------------------------------------------------------
63 // ----------------------------------------------------------------------------
65 class WXDLLEXPORT wxCursorRefData
: public wxGDIImageRefData
68 // the second parameter is used to tell us to delete the cursor when we're
69 // done with it (normally we shouldn't call DestroyCursor() this is why it
70 // doesn't happen by default)
71 wxCursorRefData(HCURSOR hcursor
= 0, bool takeOwnership
= false);
73 virtual ~wxCursorRefData() { Free(); }
78 // return the size of the standard cursor: notice that the system only
79 // supports the cursors of this size
80 static wxCoord
GetStandardWidth();
81 static wxCoord
GetStandardHeight();
86 // standard cursor size, computed on first use
87 static wxSize ms_sizeStd
;
90 // ----------------------------------------------------------------------------
92 // ----------------------------------------------------------------------------
94 IMPLEMENT_DYNAMIC_CLASS(wxCursor
, wxGDIObject
)
96 // ----------------------------------------------------------------------------
98 // ----------------------------------------------------------------------------
100 // Current cursor, in order to hang on to cursor handle when setting the cursor
102 static wxCursor
*gs_globalCursor
= NULL
;
104 // ----------------------------------------------------------------------------
106 // ----------------------------------------------------------------------------
108 class wxCursorModule
: public wxModule
111 virtual bool OnInit()
113 gs_globalCursor
= new wxCursor
;
118 virtual void OnExit()
120 delete gs_globalCursor
;
121 gs_globalCursor
= (wxCursor
*)NULL
;
125 // ----------------------------------------------------------------------------
127 // ----------------------------------------------------------------------------
129 wxDECLARE_SCOPED_ARRAY(unsigned char, ByteArray
);
130 wxDEFINE_SCOPED_ARRAY(unsigned char, ByteArray
);
132 // ============================================================================
134 // ============================================================================
136 // ----------------------------------------------------------------------------
138 // ----------------------------------------------------------------------------
140 wxSize
wxCursorRefData::ms_sizeStd
;
142 wxCoord
wxCursorRefData::GetStandardWidth()
145 ms_sizeStd
.x
= wxSystemSettings::GetMetric(wxSYS_CURSOR_X
);
150 wxCoord
wxCursorRefData::GetStandardHeight()
153 ms_sizeStd
.y
= wxSystemSettings::GetMetric(wxSYS_CURSOR_Y
);
158 wxCursorRefData::wxCursorRefData(HCURSOR hcursor
, bool destroy
)
160 m_hCursor
= (WXHCURSOR
)hcursor
;
164 m_width
= GetStandardWidth();
165 m_height
= GetStandardHeight();
168 m_destroyCursor
= destroy
;
171 void wxCursorRefData::Free()
175 if ( m_destroyCursor
)
176 ::DestroyCursor((HCURSOR
)m_hCursor
);
182 // ----------------------------------------------------------------------------
184 // ----------------------------------------------------------------------------
190 wxCursor::wxCursor(const wxImage
& image
)
192 // image has to be of the standard cursor size, otherwise we won't be able
194 const int w
= wxCursorRefData::GetStandardWidth();
195 const int h
= wxCursorRefData::GetStandardHeight();
197 wxImage image32
= image
.Scale(w
, h
);
199 const int imagebitcount
= (w
*h
)/8;
201 ByteArray
bits(new unsigned char [imagebitcount
]),
202 maskBits(new unsigned char [imagebitcount
]);
205 unsigned char c
, cMask
;
207 const unsigned char * const rgbBits
= image32
.GetData();
209 // first create the XOR mask
210 for ( i
= 0; i
< imagebitcount
; i
++ )
214 // unlike gtk, the pixels go in the opposite order in the bytes
216 for ( j
= 0; j
< 8; j
++ )
218 // possible overflow if we do the summation first ?
219 c
= rgbBits
[(i8
+j
)*3]/3 +
220 rgbBits
[(i8
+j
)*3+1]/3 +
221 rgbBits
[(i8
+j
)*3+2]/3;
223 // if average value is > mid grey
225 bits
[i
] = bits
[i
] | cMask
;
231 if ( image32
.HasMask() )
233 unsigned char r
= image32
.GetMaskRed(),
234 g
= image32
.GetMaskGreen(),
235 b
= image32
.GetMaskBlue();
237 for ( i
= 0; i
< imagebitcount
; i
++ )
243 for ( j
= 0; j
< 8; j
++ )
245 if ( rgbBits
[(i8
+j
)*3] == r
&&
246 rgbBits
[(i8
+j
)*3+1] == g
&&
247 rgbBits
[(i8
+j
)*3+2] == b
)
249 maskBits
[i
] = maskBits
[i
] | cMask
;
256 else // no mask in the image
258 memset(maskBits
.get(), 0, sizeof(unsigned char)*imagebitcount
);
261 // determine where should the cursors hot spot be
262 int hotSpotX
= image32
.GetOptionInt(wxCUR_HOTSPOT_X
);
263 int hotSpotY
= image32
.GetOptionInt(wxCUR_HOTSPOT_Y
);
264 if (hotSpotX
< 0 || hotSpotX
>= w
)
266 if (hotSpotY
< 0 || hotSpotY
>= h
)
269 // do create cursor now
270 HCURSOR hcursor
= ::CreateCursor
275 /* AND */ maskBits
.get(),
281 wxLogLastError(_T("CreateCursor"));
285 m_refData
= new wxCursorRefData(hcursor
, true /* delete it */);
289 wxCursor::wxCursor(const char WXUNUSED(bits
)[],
291 int WXUNUSED(height
),
292 int WXUNUSED(hotSpotX
), int WXUNUSED(hotSpotY
),
293 const char WXUNUSED(maskBits
)[])
297 // MicroWin doesn't have support needed for the other ctors
298 #ifdef __WXMICROWIN__
300 wxCursor::wxCursor(const wxString
& WXUNUSED(filename
),
302 int WXUNUSED(hotSpotX
),
303 int WXUNUSED(hotSpotY
))
307 wxCursor::wxCursor(int WXUNUSED(cursor_type
))
311 #else // !__WXMICROWIN__
313 wxCursor::wxCursor(const wxString
& filename
,
321 case wxBITMAP_TYPE_CUR_RESOURCE
:
322 hcursor
= ::LoadCursor(wxGetInstance(), filename
);
325 case wxBITMAP_TYPE_CUR
:
326 hcursor
= ::LoadCursorFromFile(filename
);
329 case wxBITMAP_TYPE_ICO
:
330 #if wxUSE_RESOURCE_LOADING_IN_MSW
331 hcursor
= IconToCursor((wxChar
*)filename
.c_str(),
335 #endif // wxUSE_RESOURCE_LOADING_IN_MSW
338 case wxBITMAP_TYPE_BMP
:
340 #if wxUSE_RESOURCE_LOADING_IN_MSW
342 HPALETTE hPalette
= 0;
343 if ( wxReadDIB((wxChar
*)filename
.c_str(), &hBitmap
, &hPalette
) )
346 DeleteObject(hPalette
);
351 hcursor
= MakeCursorFromBitmap(wxGetInstance(), hBitmap
, &pt
);
352 DeleteObject(hBitmap
);
353 #endif // wxUSE_RESOURCE_LOADING_IN_MSW
363 wxFAIL_MSG( _T("unknown cursor resource type") );
370 m_refData
= new wxCursorRefData(hcursor
, true /* delete it later */);
372 #if WXWIN_COMPATIBILITY_2
374 #endif // WXWIN_COMPATIBILITY_2
378 // Cursors by stock number
379 wxCursor::wxCursor(int idCursor
)
381 // all wxWindows standard cursors
382 static const struct StdCursor
384 // is this a standard Windows cursor?
387 // the cursor name or id
391 { true, NULL
}, // wxCURSOR_NONE
392 { true, IDC_ARROW
}, // wxCURSOR_ARROW
393 { false, _T("wxCURSOR_RIGHT_ARROW") }, // wxCURSOR_RIGHT_ARROW
394 { false, _T("wxCURSOR_BULLSEYE") }, // wxCURSOR_BULLSEYE
395 { true, IDC_ARROW
}, // wxCURSOR_CHAR
396 { true, IDC_CROSS
}, // wxCURSOR_CROSS
397 { false, _T("wxCURSOR_HAND") }, // wxCURSOR_HAND
398 { true, IDC_IBEAM
}, // wxCURSOR_IBEAM
399 { true, IDC_ARROW
}, // wxCURSOR_LEFT_BUTTON
400 { false, _T("wxCURSOR_MAGNIFIER") }, // wxCURSOR_MAGNIFIER
401 { true, IDC_ARROW
}, // wxCURSOR_MIDDLE_BUTTON
402 { true, IDC_NO
}, // wxCURSOR_NO_ENTRY
403 { false, _T("wxCURSOR_PAINT_BRUSH") }, // wxCURSOR_PAINT_BRUSH
404 { false, _T("wxCURSOR_PENCIL") }, // wxCURSOR_PENCIL
405 { false, _T("wxCURSOR_POINT_LEFT") }, // wxCURSOR_POINT_LEFT
406 { false, _T("wxCURSOR_POINT_RIGHT") }, // wxCURSOR_POINT_RIGHT
407 { true, IDC_HELP
}, // wxCURSOR_QUESTION_ARROW
408 { true, IDC_ARROW
}, // wxCURSOR_RIGHT_BUTTON
409 { true, IDC_SIZENESW
}, // wxCURSOR_SIZENESW
410 { true, IDC_SIZENS
}, // wxCURSOR_SIZENS
411 { true, IDC_SIZENWSE
}, // wxCURSOR_SIZENWSE
412 { true, IDC_SIZEWE
}, // wxCURSOR_SIZEWE
413 { true, IDC_SIZEALL
}, // wxCURSOR_SIZING
414 { false, _T("wxCURSOR_SPRAYCAN") }, // wxCURSOR_SPRAYCAN
415 { true, IDC_WAIT
}, // wxCURSOR_WAIT
416 { true, IDC_WAIT
}, // wxCURSOR_WATCH
417 { false, _T("wxCURSOR_BLANK") }, // wxCURSOR_BLANK
418 { true, IDC_APPSTARTING
}, // wxCURSOR_ARROWWAIT
420 // no entry for wxCURSOR_MAX
423 wxCOMPILE_TIME_ASSERT( WXSIZEOF(stdCursors
) == wxCURSOR_MAX
,
424 CursorsIdArrayMismatch
);
426 wxCHECK_RET( idCursor
> 0 && (size_t)idCursor
< WXSIZEOF(stdCursors
),
427 _T("invalid cursor id in wxCursor() ctor") );
429 const StdCursor
& stdCursor
= stdCursors
[idCursor
];
431 HCURSOR hcursor
= ::LoadCursor(stdCursor
.isStd
? NULL
: wxGetInstance(),
436 wxLogLastError(_T("LoadCursor"));
440 m_refData
= new wxCursorRefData(hcursor
);
444 #endif // __WXMICROWIN__/!__WXMICROWIN__
446 wxCursor::~wxCursor()
450 // ----------------------------------------------------------------------------
451 // other wxCursor functions
452 // ----------------------------------------------------------------------------
454 bool wxCursor::operator==(const wxCursor
& cursor
) const
457 return !cursor
.m_refData
;
459 return cursor
.m_refData
&&
460 ((wxCursorRefData
*)m_refData
)->m_hCursor
==
461 ((wxCursorRefData
*)cursor
.m_refData
)->m_hCursor
;
464 wxGDIImageRefData
*wxCursor::CreateData() const
466 return new wxCursorRefData
;
469 // ----------------------------------------------------------------------------
470 // Global cursor setting
471 // ----------------------------------------------------------------------------
473 const wxCursor
*wxGetGlobalCursor()
475 return gs_globalCursor
;
478 void wxSetCursor(const wxCursor
& cursor
)
482 ::SetCursor(GetHcursorOf(cursor
));
484 if ( gs_globalCursor
)
485 *gs_globalCursor
= cursor
;