1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk1/cursor.cpp
4 // Author: Robert Roebling
5 // Copyright: (c) 1998 Robert Roebling
6 // Licence: wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
9 // For compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
12 #include "wx/cursor.h"
22 //-----------------------------------------------------------------------------
24 //-----------------------------------------------------------------------------
26 extern void wxapp_install_idle_handler();
29 //-----------------------------------------------------------------------------
31 //-----------------------------------------------------------------------------
33 class wxCursorRefData
: public wxGDIRefData
37 virtual ~wxCursorRefData();
42 // There is no way to copy m_cursor so we can't implement a copy ctor
44 wxDECLARE_NO_COPY_CLASS(wxCursorRefData
);
47 wxCursorRefData::wxCursorRefData()
52 wxCursorRefData::~wxCursorRefData()
54 if (m_cursor
) gdk_cursor_destroy( m_cursor
);
57 //-----------------------------------------------------------------------------
59 #define M_CURSORDATA ((wxCursorRefData *)m_refData)
61 IMPLEMENT_DYNAMIC_CLASS(wxCursor
,wxObject
)
68 void wxCursor::InitFromStock( wxStockCursor cursorId
)
70 m_refData
= new wxCursorRefData();
72 GdkCursorType gdk_cur
= GDK_LEFT_PTR
;
77 static const gchar bits
[] = { 0 };
78 static /* const -- not in GTK1 */ GdkColor color
= { 0, 0, 0, 0 };
80 GdkPixmap
*pixmap
= gdk_bitmap_create_from_data(NULL
, bits
, 1, 1);
81 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixmap(pixmap
,
89 case wxCURSOR_ARROW
: // fall through to default
90 case wxCURSOR_DEFAULT
: gdk_cur
= GDK_LEFT_PTR
; break;
91 case wxCURSOR_RIGHT_ARROW
: gdk_cur
= GDK_RIGHT_PTR
; break;
92 case wxCURSOR_HAND
: gdk_cur
= GDK_HAND1
; break;
93 case wxCURSOR_CROSS
: gdk_cur
= GDK_CROSSHAIR
; break;
94 case wxCURSOR_SIZEWE
: gdk_cur
= GDK_SB_H_DOUBLE_ARROW
; break;
95 case wxCURSOR_SIZENS
: gdk_cur
= GDK_SB_V_DOUBLE_ARROW
; break;
96 case wxCURSOR_ARROWWAIT
:
98 case wxCURSOR_WATCH
: gdk_cur
= GDK_WATCH
; break;
99 case wxCURSOR_SIZING
: gdk_cur
= GDK_SIZING
; break;
100 case wxCURSOR_SPRAYCAN
: gdk_cur
= GDK_SPRAYCAN
; break;
101 case wxCURSOR_IBEAM
: gdk_cur
= GDK_XTERM
; break;
102 case wxCURSOR_PENCIL
: gdk_cur
= GDK_PENCIL
; break;
103 case wxCURSOR_NO_ENTRY
: gdk_cur
= GDK_PIRATE
; break;
104 case wxCURSOR_SIZENWSE
:
105 case wxCURSOR_SIZENESW
: gdk_cur
= GDK_FLEUR
; break;
106 case wxCURSOR_QUESTION_ARROW
: gdk_cur
= GDK_QUESTION_ARROW
; break;
107 case wxCURSOR_PAINT_BRUSH
: gdk_cur
= GDK_SPRAYCAN
; break;
108 case wxCURSOR_MAGNIFIER
: gdk_cur
= GDK_PLUS
; break;
109 case wxCURSOR_CHAR
: gdk_cur
= GDK_XTERM
; break;
110 case wxCURSOR_LEFT_BUTTON
: gdk_cur
= GDK_LEFTBUTTON
; break;
111 case wxCURSOR_MIDDLE_BUTTON
: gdk_cur
= GDK_MIDDLEBUTTON
; break;
112 case wxCURSOR_RIGHT_BUTTON
: gdk_cur
= GDK_RIGHTBUTTON
; break;
113 case wxCURSOR_BULLSEYE
: gdk_cur
= GDK_TARGET
; break;
115 case wxCURSOR_POINT_LEFT
: gdk_cur
= GDK_SB_LEFT_ARROW
; break;
116 case wxCURSOR_POINT_RIGHT
: gdk_cur
= GDK_SB_RIGHT_ARROW
; break;
118 case wxCURSOR_DOUBLE_ARROW: gdk_cur = GDK_DOUBLE_ARROW; break;
119 case wxCURSOR_CROSS_REVERSE: gdk_cur = GDK_CROSS_REVERSE; break;
120 case wxCURSOR_BASED_ARROW_UP: gdk_cur = GDK_BASED_ARROW_UP; break;
121 case wxCURSOR_BASED_ARROW_DOWN: gdk_cur = GDK_BASED_ARROW_DOWN; break;
125 wxFAIL_MSG(wxT("unsupported cursor type"));
126 // will use the standard one
130 M_CURSORDATA
->m_cursor
= gdk_cursor_new( gdk_cur
);
133 extern GtkWidget
*wxGetRootWindow();
135 wxCursor::wxCursor(const char bits
[], int width
, int height
,
136 int hotSpotX
, int hotSpotY
,
137 const char maskBits
[], const wxColour
*fg
, const wxColour
*bg
)
145 if (hotSpotX
< 0 || hotSpotX
>= width
)
147 if (hotSpotY
< 0 || hotSpotY
>= height
)
150 GdkBitmap
*data
= gdk_bitmap_create_from_data( wxGetRootWindow()->window
, (gchar
*) bits
, width
, height
);
151 GdkBitmap
*mask
= gdk_bitmap_create_from_data( wxGetRootWindow()->window
, (gchar
*) maskBits
, width
, height
);
153 m_refData
= new wxCursorRefData
;
154 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixmap(
155 data
, mask
, fg
->GetColor(), bg
->GetColor(),
156 hotSpotX
, hotSpotY
);
158 gdk_bitmap_unref( data
);
159 gdk_bitmap_unref( mask
);
164 wxCursor::wxCursor( const wxImage
& image
)
166 unsigned char * rgbBits
= image
.GetData();
167 int w
= image
.GetWidth() ;
168 int h
= image
.GetHeight();
169 bool bHasMask
= image
.HasMask();
170 int imagebitcount
= (w
*h
)/8;
172 unsigned char * bits
= new unsigned char [imagebitcount
];
173 unsigned char * maskBits
= new unsigned char [imagebitcount
];
175 int i
, j
, i8
; unsigned char c
, cMask
;
176 for (i
=0; i
<imagebitcount
; i
++)
184 // possible overflow if we do the summation first ?
185 c
= rgbBits
[(i8
+j
)*3]/3 + rgbBits
[(i8
+j
)*3+1]/3 + rgbBits
[(i8
+j
)*3+2]/3;
186 //if average value is > mid grey
188 bits
[i
] = bits
[i
] | cMask
;
193 unsigned long keyMaskColor
;
197 r
= image
.GetMaskRed(),
198 g
= image
.GetMaskGreen(),
199 b
= image
.GetMaskBlue();
201 for (i
=0; i
<imagebitcount
; i
++)
209 if (rgbBits
[(i8
+j
)*3] != r
|| rgbBits
[(i8
+j
)*3+1] != g
|| rgbBits
[(i8
+j
)*3+2] != b
)
210 maskBits
[i
] = maskBits
[i
] | cMask
;
215 keyMaskColor
= (r
<< 16) | (g
<< 8) | b
;
219 for (i
=0; i
<imagebitcount
; i
++)
222 // init it to avoid compiler warnings
226 // find the most frequent color(s)
227 wxImageHistogram histogram
;
228 image
.ComputeHistogram(histogram
);
234 long colMostFreq
= 0;
235 unsigned long nMost
= 0;
236 long colNextMostFreq
= 0;
237 unsigned long nNext
= 0;
238 for ( wxImageHistogram::iterator entry
= histogram
.begin();
239 entry
!= histogram
.end();
242 value
= entry
->second
.value
;
244 if ( !bHasMask
|| (key
!= keyMaskColor
) )
251 else if (value
> nNext
)
254 colNextMostFreq
= key
;
259 wxColour fg
= wxColour ( (unsigned char)(colMostFreq
>> 16),
260 (unsigned char)(colMostFreq
>> 8),
261 (unsigned char)(colMostFreq
) );
263 wxColour bg
= wxColour ( (unsigned char)(colNextMostFreq
>> 16),
264 (unsigned char)(colNextMostFreq
>> 8),
265 (unsigned char)(colNextMostFreq
) );
267 int fg_intensity
= fg
.Red() + fg
.Green() + fg
.Blue();
268 int bg_intensity
= bg
.Red() + bg
.Green() + bg
.Blue();
270 if (bg_intensity
> fg_intensity
)
281 if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
))
282 hotSpotX
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
);
286 if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
))
287 hotSpotY
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
);
291 if (hotSpotX
< 0 || hotSpotX
>= w
)
293 if (hotSpotY
< 0 || hotSpotY
>= h
)
296 GdkBitmap
*data
= gdk_bitmap_create_from_data(wxGetRootWindow()->window
,
297 (gchar
*) bits
, w
, h
);
298 GdkBitmap
*mask
= gdk_bitmap_create_from_data(wxGetRootWindow()->window
,
299 (gchar
*) maskBits
, w
, h
);
301 m_refData
= new wxCursorRefData
;
302 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixmap
306 fg
.GetColor(), bg
.GetColor(),
310 gdk_bitmap_unref( data
);
311 gdk_bitmap_unref( mask
);
316 #endif // wxUSE_IMAGE
318 wxCursor::~wxCursor()
322 GdkCursor
*wxCursor::GetCursor() const
324 return M_CURSORDATA
->m_cursor
;
327 wxGDIRefData
*wxCursor::CreateGDIRefData() const
329 return new wxCursorRefData
;
333 wxCursor::CloneGDIRefData(const wxGDIRefData
* WXUNUSED(data
)) const
335 wxFAIL_MSG( wxS("Cloning cursors is not implemented in wxGTK.") );
337 return new wxCursorRefData
;
340 //-----------------------------------------------------------------------------
341 // busy cursor routines
342 //-----------------------------------------------------------------------------
344 extern wxCursor g_globalCursor
;
346 static wxCursor gs_savedCursor
;
347 static int gs_busyCount
= 0;
349 const wxCursor
&wxBusyCursor::GetStoredCursor()
351 return gs_savedCursor
;
354 const wxCursor
wxBusyCursor::GetBusyCursor()
356 return wxCursor(wxCURSOR_WATCH
);
359 void wxEndBusyCursor()
361 if (--gs_busyCount
> 0)
364 wxSetCursor( gs_savedCursor
);
365 gs_savedCursor
= wxNullCursor
;
368 wxTheApp
->ProcessIdle();
371 void wxBeginBusyCursor( const wxCursor
*WXUNUSED(cursor
) )
373 if (gs_busyCount
++ > 0)
376 wxASSERT_MSG( !gs_savedCursor
.IsOk(),
377 wxT("forgot to call wxEndBusyCursor, will leak memory") );
379 gs_savedCursor
= g_globalCursor
;
381 wxSetCursor( wxCursor(wxCURSOR_WATCH
) );
384 wxTheApp
->ProcessIdle();
391 return gs_busyCount
> 0;
394 void wxSetCursor( const wxCursor
& cursor
)
397 wxapp_install_idle_handler();
399 g_globalCursor
= cursor
;