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"
22 #include "wx/gtk/private.h" //for idle stuff
24 //-----------------------------------------------------------------------------
26 //-----------------------------------------------------------------------------
28 class wxCursorRefData
: public wxObjectRefData
33 virtual ~wxCursorRefData();
38 wxCursorRefData
::wxCursorRefData()
40 m_cursor
= (GdkCursor
*) NULL
;
43 wxCursorRefData
::~wxCursorRefData()
45 if (m_cursor
) gdk_cursor_unref( m_cursor
);
48 //-----------------------------------------------------------------------------
50 #define M_CURSORDATA ((wxCursorRefData *)m_refData)
52 IMPLEMENT_DYNAMIC_CLASS(wxCursor
,wxObject
)
59 wxCursor
::wxCursor( int cursorId
)
61 m_refData
= new wxCursorRefData();
63 GdkCursorType gdk_cur
= GDK_LEFT_PTR
;
68 static const gchar bits
[] = { 0 };
69 static /* const -- not in GTK1 */ GdkColor color
= { 0, 0, 0, 0 };
71 GdkPixmap
*pixmap
= gdk_bitmap_create_from_data(NULL
, bits
, 1, 1);
72 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixmap(pixmap
,
80 case wxCURSOR_ARROW
: // fall through to default
81 case wxCURSOR_DEFAULT
: gdk_cur
= GDK_LEFT_PTR
; break;
82 case wxCURSOR_RIGHT_ARROW
: gdk_cur
= GDK_RIGHT_PTR
; break;
83 case wxCURSOR_HAND
: gdk_cur
= GDK_HAND1
; break;
84 case wxCURSOR_CROSS
: gdk_cur
= GDK_CROSSHAIR
; break;
85 case wxCURSOR_SIZEWE
: gdk_cur
= GDK_SB_H_DOUBLE_ARROW
; break;
86 case wxCURSOR_SIZENS
: gdk_cur
= GDK_SB_V_DOUBLE_ARROW
; break;
87 case wxCURSOR_ARROWWAIT
:
89 case wxCURSOR_WATCH
: gdk_cur
= GDK_WATCH
; break;
90 case wxCURSOR_SIZING
: gdk_cur
= GDK_FLEUR
; break;
91 case wxCURSOR_SPRAYCAN
: gdk_cur
= GDK_SPRAYCAN
; break;
92 case wxCURSOR_IBEAM
: gdk_cur
= GDK_XTERM
; break;
93 case wxCURSOR_PENCIL
: gdk_cur
= GDK_PENCIL
; break;
94 case wxCURSOR_NO_ENTRY
: gdk_cur
= GDK_PIRATE
; break;
95 case wxCURSOR_SIZENWSE
:
96 case wxCURSOR_SIZENESW
: gdk_cur
= GDK_FLEUR
; break;
97 case wxCURSOR_QUESTION_ARROW
: gdk_cur
= GDK_QUESTION_ARROW
; break;
98 case wxCURSOR_PAINT_BRUSH
: gdk_cur
= GDK_SPRAYCAN
; break;
99 case wxCURSOR_MAGNIFIER
: gdk_cur
= GDK_PLUS
; break;
100 case wxCURSOR_CHAR
: gdk_cur
= GDK_XTERM
; break;
101 case wxCURSOR_LEFT_BUTTON
: gdk_cur
= GDK_LEFTBUTTON
; break;
102 case wxCURSOR_MIDDLE_BUTTON
: gdk_cur
= GDK_MIDDLEBUTTON
; break;
103 case wxCURSOR_RIGHT_BUTTON
: gdk_cur
= GDK_RIGHTBUTTON
; break;
104 case wxCURSOR_BULLSEYE
: gdk_cur
= GDK_TARGET
; break;
106 case wxCURSOR_POINT_LEFT
: gdk_cur
= GDK_SB_LEFT_ARROW
; break;
107 case wxCURSOR_POINT_RIGHT
: gdk_cur
= GDK_SB_RIGHT_ARROW
; break;
109 case wxCURSOR_DOUBLE_ARROW: gdk_cur = GDK_DOUBLE_ARROW; break;
110 case wxCURSOR_CROSS_REVERSE: gdk_cur = GDK_CROSS_REVERSE; break;
111 case wxCURSOR_BASED_ARROW_UP: gdk_cur = GDK_BASED_ARROW_UP; break;
112 case wxCURSOR_BASED_ARROW_DOWN: gdk_cur = GDK_BASED_ARROW_DOWN; break;
116 wxFAIL_MSG(wxT("unsupported cursor type"));
117 // will use the standard one
121 M_CURSORDATA
->m_cursor
= gdk_cursor_new( gdk_cur
);
124 extern GtkWidget
*wxGetRootWindow();
126 wxCursor
::wxCursor(const char bits
[], int width
, int height
,
127 int hotSpotX
, int hotSpotY
,
128 const char maskBits
[], const wxColour
*fg
, const wxColour
*bg
)
136 if (hotSpotX
< 0 || hotSpotX
>= width
)
138 if (hotSpotY
< 0 || hotSpotY
>= height
)
141 GdkBitmap
*data
= gdk_bitmap_create_from_data( wxGetRootWindow()->window
, (gchar
*) bits
, width
, height
);
142 GdkBitmap
*mask
= gdk_bitmap_create_from_data( wxGetRootWindow()->window
, (gchar
*) maskBits
, width
, height
);
144 m_refData
= new wxCursorRefData
;
145 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixmap(
146 data
, mask
, fg
->GetColor(), bg
->GetColor(),
147 hotSpotX
, hotSpotY
);
149 g_object_unref (data
);
150 g_object_unref (mask
);
155 static void GetHotSpot(const wxImage
& image
, int& x
, int& y
)
157 if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
))
158 x
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
);
162 if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
))
163 y
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
);
167 if (x
< 0 || x
>= image
.GetWidth())
169 if (y
< 0 || y
>= image
.GetHeight())
173 wxCursor
::wxCursor( const wxImage
& image
)
175 unsigned char * rgbBits
= image
.GetData();
176 int w
= image
.GetWidth() ;
177 int h
= image
.GetHeight();
178 bool bHasMask
= image
.HasMask();
179 int imagebitcount
= (w
*h
)/8;
181 #if GTK_CHECK_VERSION(2,2,0)
182 if ( gdk_display_supports_cursor_color(gdk_display_get_default()) )
184 unsigned char rMask
= 0,
189 rMask
= image
.GetMaskRed();
190 gMask
= image
.GetMaskGreen();
191 bMask
= image
.GetMaskBlue();
194 GdkPixbuf
*pixbuf
= gdk_pixbuf_new(GDK_COLORSPACE_RGB
, true, 8, w
, h
);
195 unsigned char *alpha
= image
.HasAlpha() ? image
.GetAlpha() : NULL
;
196 unsigned char *out
= gdk_pixbuf_get_pixels(pixbuf
);
197 int rowpad
= gdk_pixbuf_get_rowstride(pixbuf
) - 4 * w
;
198 for ( int y
= 0; y
< h
; y
++, out
+= rowpad
)
200 for ( int x
= 0; x
< w
; x
++, out
+= 4, rgbBits
+= 3 )
206 out
[0] == rMask
&& out
[1] == gMask
&& out
[2] == bMask
)
209 out
[3] = alpha ?
*alpha
: 255;
215 int hotSpotX
, hotSpotY
;
216 GetHotSpot(image
, hotSpotX
, hotSpotY
);
218 m_refData
= new wxCursorRefData
;
219 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixbuf
221 gdk_display_get_default(),
225 g_object_unref (pixbuf
);
230 unsigned char * bits
= new unsigned char [imagebitcount
];
231 unsigned char * maskBits
= new unsigned char [imagebitcount
];
233 int i
, j
, i8
; unsigned char c
, cMask
;
234 for (i
=0; i
<imagebitcount
; i
++)
242 // possible overflow if we do the summation first ?
243 c
= rgbBits
[(i8
+j
)*3]/3 + rgbBits
[(i8
+j
)*3+1]/3 + rgbBits
[(i8
+j
)*3+2]/3;
244 //if average value is > mid grey
246 bits
[i
] = bits
[i
] | cMask
;
251 unsigned long keyMaskColor
;
255 r
= image
.GetMaskRed(),
256 g
= image
.GetMaskGreen(),
257 b
= image
.GetMaskBlue();
259 for (i
=0; i
<imagebitcount
; i
++)
267 if (rgbBits
[(i8
+j
)*3] != r
|| rgbBits
[(i8
+j
)*3+1] != g
|| rgbBits
[(i8
+j
)*3+2] != b
)
268 maskBits
[i
] = maskBits
[i
] | cMask
;
273 keyMaskColor
= (r
<< 16) | (g
<< 8) | b
;
277 for (i
=0; i
<imagebitcount
; i
++)
280 // init it to avoid compiler warnings
284 // find the most frequent color(s)
285 wxImageHistogram histogram
;
286 image
.ComputeHistogram(histogram
);
292 long colMostFreq
= 0;
293 unsigned long nMost
= 0;
294 long colNextMostFreq
= 0;
295 unsigned long nNext
= 0;
296 for ( wxImageHistogram
::iterator entry
= histogram
.begin();
297 entry
!= histogram
.end();
300 value
= entry
->second
.value
;
302 if ( !bHasMask
|| (key
!= keyMaskColor
) )
309 else if (value
> nNext
)
312 colNextMostFreq
= key
;
317 wxColour fg
= wxColour ( (unsigned char)(colMostFreq
>> 16),
318 (unsigned char)(colMostFreq
>> 8),
319 (unsigned char)(colMostFreq
) );
321 wxColour bg
= wxColour ( (unsigned char)(colNextMostFreq
>> 16),
322 (unsigned char)(colNextMostFreq
>> 8),
323 (unsigned char)(colNextMostFreq
) );
325 int fg_intensity
= fg
.Red() + fg
.Green() + fg
.Blue();
326 int bg_intensity
= bg
.Red() + bg
.Green() + bg
.Blue();
328 if (bg_intensity
> fg_intensity
)
336 int hotSpotX
, hotSpotY
;
337 GetHotSpot(image
, hotSpotX
, hotSpotY
);
339 GdkBitmap
*data
= gdk_bitmap_create_from_data(wxGetRootWindow()->window
,
340 (gchar
*) bits
, w
, h
);
341 GdkBitmap
*mask
= gdk_bitmap_create_from_data(wxGetRootWindow()->window
,
342 (gchar
*) maskBits
, w
, h
);
344 m_refData
= new wxCursorRefData
;
345 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixmap
349 fg
.GetColor(), bg
.GetColor(),
353 g_object_unref (data
);
354 g_object_unref (mask
);
359 #endif // wxUSE_IMAGE
361 wxCursor
::~wxCursor()
365 bool wxCursor
::IsOk() const
367 return (m_refData
!= NULL
);
370 GdkCursor
*wxCursor
::GetCursor() const
372 return M_CURSORDATA
->m_cursor
;
375 //-----------------------------------------------------------------------------
376 // busy cursor routines
377 //-----------------------------------------------------------------------------
379 extern wxCursor g_globalCursor
;
381 static wxCursor gs_savedCursor
;
382 static int gs_busyCount
= 0;
384 const wxCursor
&wxBusyCursor
::GetStoredCursor()
386 return gs_savedCursor
;
389 const wxCursor wxBusyCursor
::GetBusyCursor()
391 return wxCursor(wxCURSOR_WATCH
);
394 void wxEndBusyCursor()
396 if (--gs_busyCount
> 0)
399 wxSetCursor( gs_savedCursor
);
400 gs_savedCursor
= wxNullCursor
;
403 wxTheApp
->ProcessIdle();
406 void wxBeginBusyCursor( const wxCursor
*WXUNUSED(cursor
) )
408 if (gs_busyCount
++ > 0)
411 wxASSERT_MSG( !gs_savedCursor
.Ok(),
412 wxT("forgot to call wxEndBusyCursor, will leak memory") );
414 gs_savedCursor
= g_globalCursor
;
416 wxSetCursor( wxCursor(wxCURSOR_WATCH
) );
419 wxTheApp
->ProcessIdle();
426 return gs_busyCount
> 0;
429 void wxSetCursor( const wxCursor
& cursor
)
432 wxapp_install_idle_handler();
434 g_globalCursor
= cursor
;