1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
12 #pragma implementation "cursor.h"
15 #include "wx/cursor.h"
22 //-----------------------------------------------------------------------------
24 //-----------------------------------------------------------------------------
26 extern void wxapp_install_idle_handler();
29 //-----------------------------------------------------------------------------
31 //-----------------------------------------------------------------------------
33 class wxCursorRefData
: public wxObjectRefData
43 wxCursorRefData::wxCursorRefData()
45 m_cursor
= (GdkCursor
*) NULL
;
48 wxCursorRefData::~wxCursorRefData()
50 if (m_cursor
) gdk_cursor_destroy( m_cursor
);
53 //-----------------------------------------------------------------------------
55 #define M_CURSORDATA ((wxCursorRefData *)m_refData)
57 IMPLEMENT_DYNAMIC_CLASS(wxCursor
,wxObject
)
64 wxCursor::wxCursor( int cursorId
)
66 m_refData
= new wxCursorRefData();
68 GdkCursorType gdk_cur
= GDK_LEFT_PTR
;
71 case wxCURSOR_DEFAULT
: gdk_cur
= GDK_LEFT_PTR
; break;
72 case wxCURSOR_HAND
: gdk_cur
= GDK_HAND1
; break;
73 case wxCURSOR_CROSS
: gdk_cur
= GDK_CROSSHAIR
; break;
74 case wxCURSOR_SIZEWE
: gdk_cur
= GDK_SB_H_DOUBLE_ARROW
; break;
75 case wxCURSOR_SIZENS
: gdk_cur
= GDK_SB_V_DOUBLE_ARROW
; break;
76 case wxCURSOR_ARROWWAIT
:
78 case wxCURSOR_WATCH
: gdk_cur
= GDK_WATCH
; break;
79 case wxCURSOR_SIZING
: gdk_cur
= GDK_SIZING
; break;
80 case wxCURSOR_SPRAYCAN
: gdk_cur
= GDK_SPRAYCAN
; break;
81 case wxCURSOR_IBEAM
: gdk_cur
= GDK_XTERM
; break;
82 case wxCURSOR_PENCIL
: gdk_cur
= GDK_PENCIL
; break;
83 case wxCURSOR_NO_ENTRY
: gdk_cur
= GDK_PIRATE
; break;
84 case wxCURSOR_SIZENWSE
:
85 case wxCURSOR_SIZENESW
: gdk_cur
= GDK_FLEUR
; break;
86 case wxCURSOR_QUESTION_ARROW
: gdk_cur
= GDK_QUESTION_ARROW
; break;
87 case wxCURSOR_PAINT_BRUSH
: gdk_cur
= GDK_SPRAYCAN
; break;
88 case wxCURSOR_MAGNIFIER
: gdk_cur
= GDK_PLUS
; break;
89 case wxCURSOR_CHAR
: gdk_cur
= GDK_XTERM
; break;
90 case wxCURSOR_LEFT_BUTTON
: gdk_cur
= GDK_LEFTBUTTON
; break;
91 case wxCURSOR_MIDDLE_BUTTON
: gdk_cur
= GDK_MIDDLEBUTTON
; break;
92 case wxCURSOR_RIGHT_BUTTON
: gdk_cur
= GDK_RIGHTBUTTON
; break;
93 case wxCURSOR_BULLSEYE
: gdk_cur
= GDK_TARGET
; break;
95 case wxCURSOR_POINT_LEFT
: gdk_cur
= GDK_SB_LEFT_ARROW
; break;
96 case wxCURSOR_POINT_RIGHT
: gdk_cur
= GDK_SB_RIGHT_ARROW
; break;
98 case wxCURSOR_DOUBLE_ARROW: gdk_cur = GDK_DOUBLE_ARROW; break;
99 case wxCURSOR_CROSS_REVERSE: gdk_cur = GDK_CROSS_REVERSE; break;
100 case wxCURSOR_BASED_ARROW_UP: gdk_cur = GDK_BASED_ARROW_UP; break;
101 case wxCURSOR_BASED_ARROW_DOWN: gdk_cur = GDK_BASED_ARROW_DOWN; break;
104 wxFAIL_MSG(wxT("unsupported cursor type"));
105 // will use the standard one
111 M_CURSORDATA
->m_cursor
= gdk_cursor_new( gdk_cur
);
114 extern GtkWidget
*wxGetRootWindow();
116 wxCursor::wxCursor(const char bits
[], int width
, int height
,
117 int hotSpotX
, int hotSpotY
,
118 const char maskBits
[], wxColour
*fg
, wxColour
*bg
)
126 if (hotSpotX
< 0 || hotSpotX
>= width
)
128 if (hotSpotY
< 0 || hotSpotY
>= height
)
131 GdkBitmap
*data
= gdk_bitmap_create_from_data( wxGetRootWindow()->window
, (gchar
*) bits
, width
, height
);
132 GdkBitmap
*mask
= gdk_bitmap_create_from_data( wxGetRootWindow()->window
, (gchar
*) maskBits
, width
, height
);
134 m_refData
= new wxCursorRefData
;
135 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixmap(
136 data
, mask
, fg
->GetColor(), bg
->GetColor(),
137 hotSpotX
, hotSpotY
);
139 gdk_bitmap_unref( data
);
140 gdk_bitmap_unref( mask
);
144 wxCursor::wxCursor( const wxCursor
&cursor
)
150 wxCursor::wxCursor( const wxImage
& image
)
152 unsigned char * rgbBits
= image
.GetData();
153 int w
= image
.GetWidth() ;
154 int h
= image
.GetHeight() ;
155 bool bHasMask
= image
.HasMask() ;
156 int imagebitcount
= (w
*h
)/8;
158 unsigned char r
, g
, b
;
159 unsigned char * bits
= new unsigned char [imagebitcount
];
160 unsigned char * maskBits
= new unsigned char [imagebitcount
];
162 int i
,j
, i8
; unsigned char c
, cMask
;
163 for (i
=0; i
<imagebitcount
; i
++)
171 // possible overflow if we do the summation first ?
172 c
= rgbBits
[(i8
+j
)*3]/3 + rgbBits
[(i8
+j
)*3+1]/3 + rgbBits
[(i8
+j
)*3+2]/3 ;
173 //if average value is > mid grey
175 bits
[i
] = bits
[i
] | cMask
;
181 r
= image
.GetMaskRed() ;
182 g
= image
.GetMaskGreen() ;
183 b
= image
.GetMaskBlue() ;
185 for (i
=0; i
<imagebitcount
; i
++)
193 if (rgbBits
[(i8
+j
)*3] != r
|| rgbBits
[(i8
+j
)*3+1] != g
|| rgbBits
[(i8
+j
)*3+2] != b
)
194 maskBits
[i
] = maskBits
[i
] | cMask
;
201 for (i
=0; i
<imagebitcount
; i
++)
204 //find the most frequent color(s)
205 //it seems a waste of effort to copy the image
206 //but otherwise we need to remove the const modifier ??
207 wxImage tmpImage
= image
.Copy();
208 wxImageHistogram histogram
;
213 unsigned long keyMaskColor
= 0;
215 keyMaskColor
= (r
<< 16) | (g
<< 8) | b
;
217 tmpImage
.ComputeHistogram(histogram
);
219 long MostFreqCol
= 0;
220 unsigned long nMost
= 0;
221 long NextFreqCol
= 0;
222 unsigned long nNext
= 0;
223 wxImageHistogram::iterator entry
= histogram
.begin();
225 while ( entry
!= histogram
.end() )
227 value
= entry
->second
.value
;
229 if ( !bHasMask
|| (key
!= keyMaskColor
) )
236 else if (value
> nNext
)
244 wxColour fg
= wxColour ( (unsigned char)(MostFreqCol
>> 16),
245 (unsigned char)(MostFreqCol
>> 8),
246 (unsigned char)(MostFreqCol
) ) ;
248 wxColour bg
= wxColour ( (unsigned char)(NextFreqCol
>> 16),
249 (unsigned char)(NextFreqCol
>> 8),
250 (unsigned char)(NextFreqCol
) ) ;
255 if (image
.HasOption(wxCUR_HOTSPOT_X
))
256 hotSpotX
= image
.GetOptionInt(wxCUR_HOTSPOT_X
);
257 if (image
.HasOption(wxCUR_HOTSPOT_Y
))
258 hotSpotY
= image
.GetOptionInt(wxCUR_HOTSPOT_Y
);
260 if (hotSpotX
< 0 || hotSpotX
>= w
)
262 if (hotSpotY
< 0 || hotSpotY
>= h
)
265 GdkBitmap
*data
= gdk_bitmap_create_from_data( wxGetRootWindow()->window
, (gchar
*) bits
,
267 GdkBitmap
*mask
= gdk_bitmap_create_from_data( wxGetRootWindow()->window
, (gchar
*) maskBits
,
270 m_refData
= new wxCursorRefData
;
271 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixmap(
272 data
, mask
, fg
.GetColor(), bg
.GetColor(),
273 hotSpotX
, hotSpotY
);
275 gdk_bitmap_unref( data
);
276 gdk_bitmap_unref( mask
);
282 wxCursor::~wxCursor()
286 wxCursor
& wxCursor::operator = ( const wxCursor
& cursor
)
296 bool wxCursor::operator == ( const wxCursor
& cursor
) const
298 return m_refData
== cursor
.m_refData
;
301 bool wxCursor::operator != ( const wxCursor
& cursor
) const
303 return m_refData
!= cursor
.m_refData
;
306 bool wxCursor::Ok() const
308 return (m_refData
!= NULL
);
311 GdkCursor
*wxCursor::GetCursor() const
313 return M_CURSORDATA
->m_cursor
;
316 //-----------------------------------------------------------------------------
317 // busy cursor routines
318 //-----------------------------------------------------------------------------
320 extern wxCursor g_globalCursor
;
322 static wxCursor gs_savedCursor
;
323 static int gs_busyCount
= 0;
325 const wxCursor
&wxBusyCursor::GetStoredCursor()
327 return gs_savedCursor
;
330 const wxCursor
wxBusyCursor::GetBusyCursor()
332 return wxCursor(wxCURSOR_WATCH
);
335 void wxEndBusyCursor()
337 if (--gs_busyCount
> 0)
340 wxSetCursor( gs_savedCursor
);
341 gs_savedCursor
= wxNullCursor
;
344 wxTheApp
->SendIdleEvents();
347 void wxBeginBusyCursor( wxCursor
*WXUNUSED(cursor
) )
349 if (gs_busyCount
++ > 0)
352 wxASSERT_MSG( !gs_savedCursor
.Ok(),
353 wxT("forgot to call wxEndBusyCursor, will leak memory") );
355 gs_savedCursor
= g_globalCursor
;
357 wxSetCursor( wxCursor(wxCURSOR_WATCH
) );
360 wxTheApp
->SendIdleEvents();
367 return gs_busyCount
> 0;
370 void wxSetCursor( const wxCursor
& cursor
)
373 wxapp_install_idle_handler();
375 g_globalCursor
= cursor
;