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"
38 #include "wx/settings.h"
41 #include "wx/ptr_scpd.h"
43 #include "wx/module.h"
45 #include "wx/msw/private.h"
47 #ifndef __WXMICROWIN__
48 #include "wx/msw/dib.h"
51 #if wxUSE_RESOURCE_LOADING_IN_MSW
52 #include "wx/msw/curico.h"
53 #include "wx/msw/curicop.h"
56 // define functions missing in MicroWin
58 static inline void DestroyCursor(HCURSOR
) { }
59 static inline void SetCursor(HCURSOR
) { }
60 #endif // __WXMICROWIN__
62 // ----------------------------------------------------------------------------
64 // ----------------------------------------------------------------------------
66 class WXDLLEXPORT wxCursorRefData
: public wxGDIImageRefData
69 // the second parameter is used to tell us to delete the cursor when we're
70 // done with it (normally we shouldn't call DestroyCursor() this is why it
71 // doesn't happen by default)
72 wxCursorRefData(HCURSOR hcursor
= 0, bool takeOwnership
= false);
74 virtual ~wxCursorRefData() { Free(); }
79 // return the size of the standard cursor: notice that the system only
80 // supports the cursors of this size
81 static wxCoord
GetStandardWidth();
82 static wxCoord
GetStandardHeight();
87 // standard cursor size, computed on first use
88 static wxSize ms_sizeStd
;
91 // ----------------------------------------------------------------------------
93 // ----------------------------------------------------------------------------
95 IMPLEMENT_DYNAMIC_CLASS(wxCursor
, wxGDIObject
)
97 // ----------------------------------------------------------------------------
99 // ----------------------------------------------------------------------------
101 // Current cursor, in order to hang on to cursor handle when setting the cursor
103 static wxCursor
*gs_globalCursor
= NULL
;
105 // ----------------------------------------------------------------------------
107 // ----------------------------------------------------------------------------
109 class wxCursorModule
: public wxModule
112 virtual bool OnInit()
114 gs_globalCursor
= new wxCursor
;
119 virtual void OnExit()
121 delete gs_globalCursor
;
122 gs_globalCursor
= (wxCursor
*)NULL
;
126 // ----------------------------------------------------------------------------
128 // ----------------------------------------------------------------------------
130 wxDECLARE_SCOPED_ARRAY(unsigned char, ByteArray
);
131 wxDEFINE_SCOPED_ARRAY(unsigned char, ByteArray
);
133 // ============================================================================
135 // ============================================================================
137 // ----------------------------------------------------------------------------
139 // ----------------------------------------------------------------------------
141 wxSize
wxCursorRefData::ms_sizeStd
;
143 wxCoord
wxCursorRefData::GetStandardWidth()
146 ms_sizeStd
.x
= wxSystemSettings::GetMetric(wxSYS_CURSOR_X
);
151 wxCoord
wxCursorRefData::GetStandardHeight()
154 ms_sizeStd
.y
= wxSystemSettings::GetMetric(wxSYS_CURSOR_Y
);
159 wxCursorRefData::wxCursorRefData(HCURSOR hcursor
, bool destroy
)
161 m_hCursor
= (WXHCURSOR
)hcursor
;
165 m_width
= GetStandardWidth();
166 m_height
= GetStandardHeight();
169 m_destroyCursor
= destroy
;
172 void wxCursorRefData::Free()
176 if ( m_destroyCursor
)
177 ::DestroyCursor((HCURSOR
)m_hCursor
);
183 // ----------------------------------------------------------------------------
185 // ----------------------------------------------------------------------------
191 wxCursor::wxCursor(const wxImage
& image
)
193 // image has to be of the standard cursor size, otherwise we won't be able
195 const int w
= wxCursorRefData::GetStandardWidth();
196 const int h
= wxCursorRefData::GetStandardHeight();
198 wxImage image32
= image
.Scale(w
, h
);
200 const int imagebitcount
= (w
*h
)/8;
202 ByteArray
bits(new unsigned char [imagebitcount
]),
203 maskBits(new unsigned char [imagebitcount
]);
206 unsigned char c
, cMask
;
208 const unsigned char * const rgbBits
= image32
.GetData();
210 // first create the XOR mask
211 for ( i
= 0; i
< imagebitcount
; i
++ )
215 // unlike gtk, the pixels go in the opposite order in the bytes
217 for ( j
= 0; j
< 8; j
++ )
219 // possible overflow if we do the summation first ?
220 c
= rgbBits
[(i8
+j
)*3]/3 +
221 rgbBits
[(i8
+j
)*3+1]/3 +
222 rgbBits
[(i8
+j
)*3+2]/3;
224 // if average value is > mid grey
226 bits
[i
] = bits
[i
] | cMask
;
232 if ( image32
.HasMask() )
234 unsigned char r
= image32
.GetMaskRed(),
235 g
= image32
.GetMaskGreen(),
236 b
= image32
.GetMaskBlue();
238 for ( i
= 0; i
< imagebitcount
; i
++ )
244 for ( j
= 0; j
< 8; j
++ )
246 if ( rgbBits
[(i8
+j
)*3] == r
&&
247 rgbBits
[(i8
+j
)*3+1] == g
&&
248 rgbBits
[(i8
+j
)*3+2] == b
)
250 maskBits
[i
] = maskBits
[i
] | cMask
;
257 else // no mask in the image
259 memset(maskBits
.get(), 0, sizeof(unsigned char)*imagebitcount
);
262 // determine where should the cursors hot spot be
263 int hotSpotX
= image32
.GetOptionInt(wxCUR_HOTSPOT_X
);
264 int hotSpotY
= image32
.GetOptionInt(wxCUR_HOTSPOT_Y
);
265 if (hotSpotX
< 0 || hotSpotX
>= w
)
267 if (hotSpotY
< 0 || hotSpotY
>= h
)
270 // do create cursor now
271 HCURSOR hcursor
= ::CreateCursor
276 /* AND */ maskBits
.get(),
282 wxLogLastError(_T("CreateCursor"));
286 m_refData
= new wxCursorRefData(hcursor
, true /* delete it */);
290 wxCursor::wxCursor(const char WXUNUSED(bits
)[],
292 int WXUNUSED(height
),
293 int WXUNUSED(hotSpotX
), int WXUNUSED(hotSpotY
),
294 const char WXUNUSED(maskBits
)[])
298 // MicroWin doesn't have support needed for the other ctors
299 #ifdef __WXMICROWIN__
301 wxCursor::wxCursor(const wxString
& WXUNUSED(filename
),
303 int WXUNUSED(hotSpotX
),
304 int WXUNUSED(hotSpotY
))
308 wxCursor::wxCursor(int WXUNUSED(cursor_type
))
312 #else // !__WXMICROWIN__
314 wxCursor::wxCursor(const wxString
& filename
,
322 case wxBITMAP_TYPE_CUR_RESOURCE
:
323 hcursor
= ::LoadCursor(wxGetInstance(), filename
);
326 case wxBITMAP_TYPE_CUR
:
327 hcursor
= ::LoadCursorFromFile(filename
);
330 #if wxUSE_RESOURCE_LOADING_IN_MSW
331 case wxBITMAP_TYPE_ICO
:
332 hcursor
= IconToCursor((wxChar
*)filename
.c_str(),
338 case wxBITMAP_TYPE_BMP
:
341 HPALETTE hPalette
= 0;
342 if ( wxReadDIB((wxChar
*)filename
.c_str(), &hBitmap
, &hPalette
) )
345 DeleteObject(hPalette
);
350 hcursor
= MakeCursorFromBitmap(wxGetInstance(), hBitmap
, &pt
);
351 DeleteObject(hBitmap
);
359 #endif // wxUSE_RESOURCE_LOADING_IN_MSW
362 wxFAIL_MSG( _T("unknown cursor resource type") );
369 m_refData
= new wxCursorRefData(hcursor
, true /* delete it later */);
371 #if WXWIN_COMPATIBILITY_2
372 ((wxCursorRefData
*)m_refData
)->SetOk();
373 #endif // WXWIN_COMPATIBILITY_2
377 // Cursors by stock number
378 wxCursor::wxCursor(int idCursor
)
380 // all wxWindows standard cursors
381 static const struct StdCursor
383 // is this a standard Windows cursor?
386 // the cursor name or id
390 { true, NULL
}, // wxCURSOR_NONE
391 { true, IDC_ARROW
}, // wxCURSOR_ARROW
392 { false, _T("wxCURSOR_RIGHT_ARROW") }, // wxCURSOR_RIGHT_ARROW
393 { false, _T("wxCURSOR_BULLSEYE") }, // wxCURSOR_BULLSEYE
394 { true, IDC_ARROW
}, // wxCURSOR_CHAR
395 { true, IDC_CROSS
}, // wxCURSOR_CROSS
396 { false, _T("wxCURSOR_HAND") }, // wxCURSOR_HAND
397 { true, IDC_IBEAM
}, // wxCURSOR_IBEAM
398 { true, IDC_ARROW
}, // wxCURSOR_LEFT_BUTTON
399 { false, _T("wxCURSOR_MAGNIFIER") }, // wxCURSOR_MAGNIFIER
400 { true, IDC_ARROW
}, // wxCURSOR_MIDDLE_BUTTON
401 { true, IDC_NO
}, // wxCURSOR_NO_ENTRY
402 { false, _T("wxCURSOR_PAINT_BRUSH") }, // wxCURSOR_PAINT_BRUSH
403 { false, _T("wxCURSOR_PENCIL") }, // wxCURSOR_PENCIL
404 { false, _T("wxCURSOR_POINT_LEFT") }, // wxCURSOR_POINT_LEFT
405 { false, _T("wxCURSOR_POINT_RIGHT") }, // wxCURSOR_POINT_RIGHT
406 { true, IDC_HELP
}, // wxCURSOR_QUESTION_ARROW
407 { true, IDC_ARROW
}, // wxCURSOR_RIGHT_BUTTON
408 { true, IDC_SIZENESW
}, // wxCURSOR_SIZENESW
409 { true, IDC_SIZENS
}, // wxCURSOR_SIZENS
410 { true, IDC_SIZENWSE
}, // wxCURSOR_SIZENWSE
411 { true, IDC_SIZEWE
}, // wxCURSOR_SIZEWE
412 { true, IDC_SIZEALL
}, // wxCURSOR_SIZING
413 { false, _T("wxCURSOR_SPRAYCAN") }, // wxCURSOR_SPRAYCAN
414 { true, IDC_WAIT
}, // wxCURSOR_WAIT
415 { true, IDC_WAIT
}, // wxCURSOR_WATCH
416 { false, _T("wxCURSOR_BLANK") }, // wxCURSOR_BLANK
417 { true, IDC_APPSTARTING
}, // wxCURSOR_ARROWWAIT
419 // no entry for wxCURSOR_MAX
422 wxCOMPILE_TIME_ASSERT( WXSIZEOF(stdCursors
) == wxCURSOR_MAX
,
423 CursorsIdArrayMismatch
);
425 wxCHECK_RET( idCursor
> 0 && (size_t)idCursor
< WXSIZEOF(stdCursors
),
426 _T("invalid cursor id in wxCursor() ctor") );
428 const StdCursor
& stdCursor
= stdCursors
[idCursor
];
430 HCURSOR hcursor
= ::LoadCursor(stdCursor
.isStd
? NULL
: wxGetInstance(),
435 wxLogLastError(_T("LoadCursor"));
439 m_refData
= new wxCursorRefData(hcursor
);
443 #endif // __WXMICROWIN__/!__WXMICROWIN__
445 wxCursor::~wxCursor()
449 // ----------------------------------------------------------------------------
450 // other wxCursor functions
451 // ----------------------------------------------------------------------------
453 bool wxCursor::operator==(const wxCursor
& cursor
) const
456 return !cursor
.m_refData
;
458 return cursor
.m_refData
&&
459 ((wxCursorRefData
*)m_refData
)->m_hCursor
==
460 ((wxCursorRefData
*)cursor
.m_refData
)->m_hCursor
;
463 wxGDIImageRefData
*wxCursor::CreateData() const
465 return new wxCursorRefData
;
468 // ----------------------------------------------------------------------------
469 // Global cursor setting
470 // ----------------------------------------------------------------------------
472 const wxCursor
*wxGetGlobalCursor()
474 return gs_globalCursor
;
477 void wxSetCursor(const wxCursor
& cursor
)
481 ::SetCursor(GetHcursorOf(cursor
));
483 if ( gs_globalCursor
)
484 *gs_globalCursor
= cursor
;