1
/////////////////////////////////////////////////////////////////////////////
2
// Name: src/msw/cursor.cpp
3
// Purpose: wxCursor class
4
// Author: Julian Smart
7
// Copyright: (c) 1997-2003 Julian Smart and Vadim Zeitlin
8
// Licence: wxWindows licence
9
/////////////////////////////////////////////////////////////////////////////
11
// ============================================================================
13
// ============================================================================
15
// ----------------------------------------------------------------------------
17
// ----------------------------------------------------------------------------
19
// For compilers that support precompilation, includes "wx.h".
20
#include "wx/wxprec.h"
26
#include "wx/cursor.h"
31
#include "wx/bitmap.h"
33
#include "wx/settings.h"
36
#include "wx/module.h"
39
#include "wx/msw/private.h"
40
#include "wx/msw/missing.h" // IDC_HAND
42
// define functions missing in MicroWin
44
static inline void DestroyCursor(HCURSOR) { }
45
static inline void SetCursor(HCURSOR) { }
46
#endif // __WXMICROWIN__
48
// ----------------------------------------------------------------------------
50
// ----------------------------------------------------------------------------
52
class WXDLLEXPORT wxCursorRefData : public wxGDIImageRefData
55
// the second parameter is used to tell us to delete the cursor when we're
56
// done with it (normally we shouldn't call DestroyCursor() this is why it
57
// doesn't happen by default)
58
wxCursorRefData(HCURSOR hcursor = 0, bool takeOwnership = false);
60
virtual ~wxCursorRefData() { Free(); }
65
// return the size of the standard cursor: notice that the system only
66
// supports the cursors of this size
67
static wxCoord GetStandardWidth();
68
static wxCoord GetStandardHeight();
73
// standard cursor size, computed on first use
74
static wxSize ms_sizeStd;
77
// ----------------------------------------------------------------------------
79
// ----------------------------------------------------------------------------
81
IMPLEMENT_DYNAMIC_CLASS(wxCursor, wxGDIObject)
83
// ----------------------------------------------------------------------------
85
// ----------------------------------------------------------------------------
87
// Current cursor, in order to hang on to cursor handle when setting the cursor
89
static wxCursor *gs_globalCursor = NULL;
91
// ----------------------------------------------------------------------------
93
// ----------------------------------------------------------------------------
95
class wxCursorModule : public wxModule
100
gs_globalCursor = new wxCursor;
105
virtual void OnExit()
107
wxDELETE(gs_globalCursor);
111
// ============================================================================
113
// ============================================================================
115
// ----------------------------------------------------------------------------
117
// ----------------------------------------------------------------------------
119
wxSize wxCursorRefData::ms_sizeStd;
121
wxCoord wxCursorRefData::GetStandardWidth()
124
ms_sizeStd.x = wxSystemSettings::GetMetric(wxSYS_CURSOR_X);
129
wxCoord wxCursorRefData::GetStandardHeight()
132
ms_sizeStd.y = wxSystemSettings::GetMetric(wxSYS_CURSOR_Y);
137
wxCursorRefData::wxCursorRefData(HCURSOR hcursor, bool destroy)
139
m_hCursor = (WXHCURSOR)hcursor;
143
m_width = GetStandardWidth();
144
m_height = GetStandardHeight();
147
m_destroyCursor = destroy;
150
void wxCursorRefData::Free()
155
if ( m_destroyCursor )
156
::DestroyCursor((HCURSOR)m_hCursor);
163
// ----------------------------------------------------------------------------
165
// ----------------------------------------------------------------------------
172
wxCursor::wxCursor(const wxImage& image)
174
// image has to be of the standard cursor size, otherwise we won't be able
176
const int w = wxCursorRefData::GetStandardWidth();
177
const int h = wxCursorRefData::GetStandardHeight();
179
int hotSpotX = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X);
180
int hotSpotY = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y);
181
int image_w = image.GetWidth();
182
int image_h = image.GetHeight();
184
wxASSERT_MSG( hotSpotX >= 0 && hotSpotX < image_w &&
185
hotSpotY >= 0 && hotSpotY < image_h,
186
wxT("invalid cursor hot spot coordinates") );
188
wxImage imageSized(image); // final image of correct size
190
// if image is too small then place it in the center, resize it if too big
191
if ((w > image_w) && (h > image_h))
193
wxPoint offset((w - image_w)/2, (h - image_h)/2);
194
hotSpotX = hotSpotX + offset.x;
195
hotSpotY = hotSpotY + offset.y;
197
imageSized = image.Size(wxSize(w, h), offset);
199
else if ((w != image_w) || (h != image_h))
201
hotSpotX = int(hotSpotX * double(w) / double(image_w));
202
hotSpotY = int(hotSpotY * double(h) / double(image_h));
204
imageSized = image.Scale(w, h);
207
HCURSOR hcursor = wxBitmapToHCURSOR( wxBitmap(imageSized),
208
hotSpotX, hotSpotY );
212
wxLogWarning(_("Failed to create cursor."));
216
m_refData = new wxCursorRefData(hcursor, true /* delete it later */);
218
#endif // wxUSE_IMAGE
220
// MicroWin doesn't have support needed for the other ctors
221
#ifdef __WXMICROWIN__
223
wxCursor::InitFromStock(wxStockCursor WXUNUSED(cursor_type))
227
#else // !__WXMICROWIN__
229
wxCursor::wxCursor(const wxString& filename,
237
case wxBITMAP_TYPE_CUR_RESOURCE:
238
hcursor = ::LoadCursor(wxGetInstance(), filename.t_str());
242
case wxBITMAP_TYPE_ANI:
243
case wxBITMAP_TYPE_CUR:
244
hcursor = ::LoadCursorFromFile(filename.t_str());
248
case wxBITMAP_TYPE_ICO:
249
hcursor = wxBitmapToHCURSOR
251
wxIcon(filename, wxBITMAP_TYPE_ICO),
257
case wxBITMAP_TYPE_BMP:
258
hcursor = wxBitmapToHCURSOR
260
wxBitmap(filename, wxBITMAP_TYPE_BMP),
267
wxLogError( wxT("unknown cursor resource type '%d'"), kind );
274
m_refData = new wxCursorRefData(hcursor, true /* delete it later */);
281
void ReverseBitmap(HBITMAP bitmap, int width, int height)
284
SelectInHDC selBitmap(hdc, bitmap);
285
::StretchBlt(hdc, width - 1, 0, -width, height,
286
hdc, 0, 0, width, height, SRCCOPY);
289
HCURSOR CreateReverseCursor(HCURSOR cursor)
292
if ( !::GetIconInfo(cursor, &info) )
295
HCURSOR cursorRev = NULL;
298
if ( ::GetObject(info.hbmMask, sizeof(bmp), &bmp) )
300
ReverseBitmap(info.hbmMask, bmp.bmWidth, bmp.bmHeight);
302
ReverseBitmap(info.hbmColor, bmp.bmWidth, bmp.bmHeight);
303
info.xHotspot = (DWORD)bmp.bmWidth - 1 - info.xHotspot;
305
cursorRev = ::CreateIconIndirect(&info);
308
::DeleteObject(info.hbmMask);
310
::DeleteObject(info.hbmColor);
315
} // anonymous namespace
317
// Cursors by stock number
318
void wxCursor::InitFromStock(wxStockCursor idCursor)
320
// all wxWidgets standard cursors
321
static const struct StdCursor
323
// is this a standard Windows cursor?
326
// the cursor name or id
330
{ true, NULL }, // wxCURSOR_NONE
331
{ true, IDC_ARROW }, // wxCURSOR_ARROW
332
{ false, wxT("WXCURSOR_RIGHT_ARROW") }, // wxCURSOR_RIGHT_ARROW
333
{ false, wxT("WXCURSOR_BULLSEYE") }, // wxCURSOR_BULLSEYE
334
{ true, IDC_ARROW }, // WXCURSOR_CHAR
335
{ true, IDC_CROSS }, // WXCURSOR_CROSS
336
{ true, IDC_HAND }, // wxCURSOR_HAND
337
{ true, IDC_IBEAM }, // WXCURSOR_IBEAM
338
{ true, IDC_ARROW }, // WXCURSOR_LEFT_BUTTON
339
{ false, wxT("WXCURSOR_MAGNIFIER") }, // wxCURSOR_MAGNIFIER
340
{ true, IDC_ARROW }, // WXCURSOR_MIDDLE_BUTTON
341
{ true, IDC_NO }, // WXCURSOR_NO_ENTRY
342
{ false, wxT("WXCURSOR_PBRUSH") }, // wxCURSOR_PAINT_BRUSH
343
{ false, wxT("WXCURSOR_PENCIL") }, // wxCURSOR_PENCIL
344
{ false, wxT("WXCURSOR_PLEFT") }, // wxCURSOR_POINT_LEFT
345
{ false, wxT("WXCURSOR_PRIGHT") }, // wxCURSOR_POINT_RIGHT
346
{ true, IDC_HELP }, // WXCURSOR_QUESTION_ARROW
347
{ true, IDC_ARROW }, // WXCURSOR_RIGHT_BUTTON
348
{ true, IDC_SIZENESW }, // WXCURSOR_SIZENESW
349
{ true, IDC_SIZENS }, // WXCURSOR_SIZENS
350
{ true, IDC_SIZENWSE }, // WXCURSOR_SIZENWSE
351
{ true, IDC_SIZEWE }, // WXCURSOR_SIZEWE
352
{ true, IDC_SIZEALL }, // WXCURSOR_SIZING
353
{ false, wxT("WXCURSOR_PBRUSH") }, // wxCURSOR_SPRAYCAN
354
{ true, IDC_WAIT }, // WXCURSOR_WAIT
355
{ true, IDC_WAIT }, // WXCURSOR_WATCH
356
{ false, wxT("WXCURSOR_BLANK") }, // wxCURSOR_BLANK
357
{ true, IDC_APPSTARTING }, // wxCURSOR_ARROWWAIT
359
// no entry for wxCURSOR_MAX
362
wxCOMPILE_TIME_ASSERT( WXSIZEOF(stdCursors) == wxCURSOR_MAX,
363
CursorsIdArrayMismatch );
365
wxCHECK_RET( idCursor > 0 && (size_t)idCursor < WXSIZEOF(stdCursors),
366
wxT("invalid cursor id in wxCursor() ctor") );
368
const StdCursor& stdCursor = stdCursors[idCursor];
369
bool deleteLater = !stdCursor.isStd;
371
HCURSOR hcursor = ::LoadCursor(stdCursor.isStd ? NULL : wxGetInstance(),
374
// IDC_HAND may not be available on some versions of Windows.
375
if ( !hcursor && idCursor == wxCURSOR_HAND)
377
hcursor = ::LoadCursor(wxGetInstance(), wxT("WXCURSOR_HAND"));
381
if ( !hcursor && idCursor == wxCURSOR_RIGHT_ARROW)
383
hcursor = ::LoadCursor(NULL, IDC_ARROW);
386
hcursor = CreateReverseCursor(hcursor);
393
if ( !stdCursor.isStd )
395
// it may be not obvious to the programmer why did loading fail,
396
// try to help by pointing to the by far the most probable reason
397
wxFAIL_MSG(wxT("Loading a cursor defined by wxWidgets failed, ")
398
wxT("did you include include/wx/msw/wx.rc file from ")
399
wxT("your resource file?"));
402
wxLogLastError(wxT("LoadCursor"));
406
m_refData = new wxCursorRefData(hcursor, deleteLater);
410
#endif // __WXMICROWIN__/!__WXMICROWIN__
412
wxCursor::~wxCursor()
416
// ----------------------------------------------------------------------------
417
// other wxCursor functions
418
// ----------------------------------------------------------------------------
420
wxGDIImageRefData *wxCursor::CreateData() const
422
return new wxCursorRefData;
425
// ----------------------------------------------------------------------------
426
// Global cursor setting
427
// ----------------------------------------------------------------------------
429
const wxCursor *wxGetGlobalCursor()
431
return gs_globalCursor;
434
void wxSetCursor(const wxCursor& cursor)
438
::SetCursor(GetHcursorOf(cursor));
440
if ( gs_globalCursor )
441
*gs_globalCursor = cursor;