1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/cursor.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
13 #include "wx/cursor.h"
19 #include "wx/colour.h"
20 #include "wx/bitmap.h"
25 //-----------------------------------------------------------------------------
27 //-----------------------------------------------------------------------------
29 class wxCursorRefData
: public wxGDIRefData
33 virtual ~wxCursorRefData();
35 virtual bool IsOk() const { return m_cursor
!= NULL
; }
40 wxCursorRefData
::wxCursorRefData()
42 m_cursor
= (GdkCursor
*) NULL
;
45 wxCursorRefData
::~wxCursorRefData()
47 if (m_cursor
) gdk_cursor_unref( m_cursor
);
50 //-----------------------------------------------------------------------------
52 #define M_CURSORDATA wx_static_cast(wxCursorRefData*, m_refData)
54 IMPLEMENT_DYNAMIC_CLASS(wxCursor
, wxGDIObject
)
60 wxCursor
::wxCursor( int cursorId
)
62 m_refData
= new wxCursorRefData();
64 GdkCursorType gdk_cur
= GDK_LEFT_PTR
;
69 const char bits
[] = { 0 };
70 const GdkColor color
= { 0, 0, 0, 0 };
72 GdkPixmap
*pixmap
= gdk_bitmap_create_from_data(NULL
, bits
, 1, 1);
73 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixmap(pixmap
,
78 g_object_unref(pixmap
);
82 case wxCURSOR_ARROW
: // fall through to default
83 case wxCURSOR_DEFAULT
: gdk_cur
= GDK_LEFT_PTR
; break;
84 case wxCURSOR_RIGHT_ARROW
: gdk_cur
= GDK_RIGHT_PTR
; break;
85 case wxCURSOR_HAND
: gdk_cur
= GDK_HAND1
; break;
86 case wxCURSOR_CROSS
: gdk_cur
= GDK_CROSSHAIR
; break;
87 case wxCURSOR_SIZEWE
: gdk_cur
= GDK_SB_H_DOUBLE_ARROW
; break;
88 case wxCURSOR_SIZENS
: gdk_cur
= GDK_SB_V_DOUBLE_ARROW
; break;
89 case wxCURSOR_ARROWWAIT
:
91 case wxCURSOR_WATCH
: gdk_cur
= GDK_WATCH
; break;
92 case wxCURSOR_SIZING
: gdk_cur
= GDK_SIZING
; break;
93 case wxCURSOR_SPRAYCAN
: gdk_cur
= GDK_SPRAYCAN
; break;
94 case wxCURSOR_IBEAM
: gdk_cur
= GDK_XTERM
; break;
95 case wxCURSOR_PENCIL
: gdk_cur
= GDK_PENCIL
; break;
96 case wxCURSOR_NO_ENTRY
: gdk_cur
= GDK_PIRATE
; break;
97 case wxCURSOR_SIZENWSE
:
98 case wxCURSOR_SIZENESW
: gdk_cur
= GDK_FLEUR
; break;
99 case wxCURSOR_QUESTION_ARROW
: gdk_cur
= GDK_QUESTION_ARROW
; break;
100 case wxCURSOR_PAINT_BRUSH
: gdk_cur
= GDK_SPRAYCAN
; break;
101 case wxCURSOR_MAGNIFIER
: gdk_cur
= GDK_PLUS
; break;
102 case wxCURSOR_CHAR
: gdk_cur
= GDK_XTERM
; break;
103 case wxCURSOR_LEFT_BUTTON
: gdk_cur
= GDK_LEFTBUTTON
; break;
104 case wxCURSOR_MIDDLE_BUTTON
: gdk_cur
= GDK_MIDDLEBUTTON
; break;
105 case wxCURSOR_RIGHT_BUTTON
: gdk_cur
= GDK_RIGHTBUTTON
; break;
106 case wxCURSOR_BULLSEYE
: gdk_cur
= GDK_TARGET
; break;
108 case wxCURSOR_POINT_LEFT
: gdk_cur
= GDK_SB_LEFT_ARROW
; break;
109 case wxCURSOR_POINT_RIGHT
: gdk_cur
= GDK_SB_RIGHT_ARROW
; break;
111 case wxCURSOR_DOUBLE_ARROW: gdk_cur = GDK_DOUBLE_ARROW; break;
112 case wxCURSOR_CROSS_REVERSE: gdk_cur = GDK_CROSS_REVERSE; break;
113 case wxCURSOR_BASED_ARROW_UP: gdk_cur = GDK_BASED_ARROW_UP; break;
114 case wxCURSOR_BASED_ARROW_DOWN: gdk_cur = GDK_BASED_ARROW_DOWN; break;
118 wxFAIL_MSG(wxT("unsupported cursor type"));
119 // will use the standard one
123 M_CURSORDATA
->m_cursor
= gdk_cursor_new( gdk_cur
);
126 extern GtkWidget
*wxGetRootWindow();
128 wxCursor
::wxCursor(const char bits
[], int width
, int height
,
129 int hotSpotX
, int hotSpotY
,
130 const char maskBits
[], const wxColour
*fg
, const wxColour
*bg
)
138 if (hotSpotX
< 0 || hotSpotX
>= width
)
140 if (hotSpotY
< 0 || hotSpotY
>= height
)
143 GdkBitmap
*data
= gdk_bitmap_create_from_data( wxGetRootWindow()->window
, (gchar
*) bits
, width
, height
);
144 GdkBitmap
*mask
= gdk_bitmap_create_from_data( wxGetRootWindow()->window
, (gchar
*) maskBits
, width
, height
);
146 m_refData
= new wxCursorRefData
;
147 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixmap(
148 data
, mask
, fg
->GetColor(), bg
->GetColor(),
149 hotSpotX
, hotSpotY
);
151 g_object_unref (data
);
152 g_object_unref (mask
);
157 static void GetHotSpot(const wxImage
& image
, int& x
, int& y
)
159 if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
))
160 x
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
);
164 if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
))
165 y
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
);
169 if (x
< 0 || x
>= image
.GetWidth())
171 if (y
< 0 || y
>= image
.GetHeight())
175 wxCursor
::wxCursor( const wxImage
& image
)
177 int w
= image
.GetWidth() ;
178 int h
= image
.GetHeight();
179 bool bHasMask
= image
.HasMask();
180 int hotSpotX
, hotSpotY
;
181 GetHotSpot(image
, hotSpotX
, hotSpotY
);
182 m_refData
= new wxCursorRefData
;
183 wxImage
image_copy(image
);
185 GdkDisplay
* display
= gdk_drawable_get_display(wxGetRootWindow()->window
);
186 if (gdk_display_supports_cursor_color(display
))
188 if (!image
.HasAlpha())
190 // add alpha, so wxBitmap will convert to pixbuf format
191 image_copy
.InitAlpha();
193 wxBitmap
bitmap(image_copy
);
194 wxASSERT(bitmap
.HasPixbuf());
195 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixbuf
204 // modify image so wxBitmap can be used to convert to pixmap
205 image_copy
.UnShare();
207 wxByte
* data
= image_copy
.GetData();
208 for (j
= 0; j
< h
; j
++)
210 for (i
= 0; i
< w
; i
++, data
+= 3)
212 //if average value is > mid grey
213 if (int(data
[0]) + data
[1] + data
[2] >= 3 * 128)
215 // wxBitmap only converts (255,255,255) to white
223 wxBitmap
bitmap(image_copy
, 1);
225 unsigned long keyMaskColor
= 0;
229 keyMaskColor
= wxImageHistogram
::MakeKey(
230 image
.GetMaskRed(), image
.GetMaskGreen(), image
.GetMaskBlue());
231 mask
= bitmap
.GetMask()->GetBitmap();
236 const int size
= ((w
+ 7) / 8) * h
;
237 char* bits
= new char[size
];
238 memset(bits
, 0xff, size
);
239 mask
= gdk_bitmap_create_from_data(
240 bitmap
.GetPixmap(), bits
, w
, h
);
244 // find the most frequent color(s)
245 wxImageHistogram histogram
;
246 image
.ComputeHistogram(histogram
);
248 long colMostFreq
= 0;
249 unsigned long nMost
= 0;
250 long colNextMostFreq
= 0;
251 unsigned long nNext
= 0;
252 for ( wxImageHistogram
::iterator entry
= histogram
.begin();
253 entry
!= histogram
.end();
256 unsigned long key
= entry
->first
;
257 if ( !bHasMask
|| (key
!= keyMaskColor
) )
259 unsigned long value
= entry
->second
.value
;
263 colNextMostFreq
= colMostFreq
;
267 else if (value
> nNext
)
270 colNextMostFreq
= key
;
275 wxColour fg
= wxColour ( (unsigned char)(colMostFreq
>> 16),
276 (unsigned char)(colMostFreq
>> 8),
277 (unsigned char)(colMostFreq
) );
279 wxColour bg
= wxColour ( (unsigned char)(colNextMostFreq
>> 16),
280 (unsigned char)(colNextMostFreq
>> 8),
281 (unsigned char)(colNextMostFreq
) );
283 int fg_intensity
= fg
.Red() + fg
.Green() + fg
.Blue();
284 int bg_intensity
= bg
.Red() + bg
.Green() + bg
.Blue();
286 if (bg_intensity
> fg_intensity
)
294 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixmap
298 fg
.GetColor(), bg
.GetColor(),
302 g_object_unref (mask
);
305 #endif // wxUSE_IMAGE
307 wxCursor
::~wxCursor()
311 GdkCursor
*wxCursor
::GetCursor() const
313 return M_CURSORDATA
->m_cursor
;
316 wxGDIRefData
*wxCursor
::CreateGDIRefData() const
318 return new wxCursorRefData
;
321 wxGDIRefData
*wxCursor
::CloneGDIRefData(const wxGDIRefData
*data
) const
323 return new wxCursorRefData(*wx_static_cast(const wxCursorRefData
*, data
));
326 //-----------------------------------------------------------------------------
327 // busy cursor routines
328 //-----------------------------------------------------------------------------
330 /* Current cursor, in order to hang on to
331 * cursor handle when setting the cursor globally */
332 wxCursor g_globalCursor
;
334 static wxCursor gs_savedCursor
;
335 static int gs_busyCount
= 0;
337 const wxCursor
&wxBusyCursor
::GetStoredCursor()
339 return gs_savedCursor
;
342 const wxCursor wxBusyCursor
::GetBusyCursor()
344 return wxCursor(wxCURSOR_WATCH
);
347 void wxEndBusyCursor()
349 if (--gs_busyCount
> 0)
352 wxSetCursor( gs_savedCursor
);
353 gs_savedCursor
= wxNullCursor
;
356 wxTheApp
->ProcessIdle();
359 void wxBeginBusyCursor( const wxCursor
*WXUNUSED(cursor
) )
361 if (gs_busyCount
++ > 0)
364 wxASSERT_MSG( !gs_savedCursor
.Ok(),
365 wxT("forgot to call wxEndBusyCursor, will leak memory") );
367 gs_savedCursor
= g_globalCursor
;
369 wxSetCursor( wxCursor(wxCURSOR_WATCH
) );
372 wxTheApp
->ProcessIdle();
379 return gs_busyCount
> 0;
382 void wxSetCursor( const wxCursor
& cursor
)
384 g_globalCursor
= cursor
;
385 wxTheApp
->WakeUpIdle();