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" 
  20 #include "wx/gtk/private.h" //for idle stuff 
  25 //----------------------------------------------------------------------------- 
  27 //----------------------------------------------------------------------------- 
  29 class wxCursorRefData
: public wxObjectRefData
 
  39 wxCursorRefData::wxCursorRefData() 
  41     m_cursor 
= (GdkCursor 
*) NULL
; 
  44 wxCursorRefData::~wxCursorRefData() 
  46     if (m_cursor
) gdk_cursor_unref( m_cursor 
); 
  49 //----------------------------------------------------------------------------- 
  51 #define M_CURSORDATA ((wxCursorRefData *)m_refData) 
  53 IMPLEMENT_DYNAMIC_CLASS(wxCursor
,wxObject
) 
  60 wxCursor::wxCursor( int cursorId 
) 
  62     m_refData 
= new wxCursorRefData(); 
  64     GdkCursorType gdk_cur 
= GDK_LEFT_PTR
; 
  69                 static const gchar bits
[] = { 0 }; 
  70                 static /* const -- not in GTK1 */ 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
, 
  81         case wxCURSOR_ARROW
:            // fall through to default 
  82         case wxCURSOR_DEFAULT
:          gdk_cur 
= GDK_LEFT_PTR
; break; 
  83         case wxCURSOR_RIGHT_ARROW
:      gdk_cur 
= GDK_RIGHT_PTR
; break; 
  84         case wxCURSOR_HAND
:             gdk_cur 
= GDK_HAND1
; break; 
  85         case wxCURSOR_CROSS
:            gdk_cur 
= GDK_CROSSHAIR
; break; 
  86         case wxCURSOR_SIZEWE
:           gdk_cur 
= GDK_SB_H_DOUBLE_ARROW
; break; 
  87         case wxCURSOR_SIZENS
:           gdk_cur 
= GDK_SB_V_DOUBLE_ARROW
; break; 
  88         case wxCURSOR_ARROWWAIT
: 
  90         case wxCURSOR_WATCH
:            gdk_cur 
= GDK_WATCH
; break; 
  91         case wxCURSOR_SIZING
:           gdk_cur 
= GDK_SIZING
; break; 
  92         case wxCURSOR_SPRAYCAN
:         gdk_cur 
= GDK_SPRAYCAN
; break; 
  93         case wxCURSOR_IBEAM
:            gdk_cur 
= GDK_XTERM
; break; 
  94         case wxCURSOR_PENCIL
:           gdk_cur 
= GDK_PENCIL
; break; 
  95         case wxCURSOR_NO_ENTRY
:         gdk_cur 
= GDK_PIRATE
; break; 
  96         case wxCURSOR_SIZENWSE
: 
  97         case wxCURSOR_SIZENESW
:         gdk_cur 
= GDK_FLEUR
; break; 
  98         case wxCURSOR_QUESTION_ARROW
:   gdk_cur 
= GDK_QUESTION_ARROW
; break; 
  99         case wxCURSOR_PAINT_BRUSH
:      gdk_cur 
= GDK_SPRAYCAN
; break; 
 100         case wxCURSOR_MAGNIFIER
:        gdk_cur 
= GDK_PLUS
; break; 
 101         case wxCURSOR_CHAR
:             gdk_cur 
= GDK_XTERM
; break; 
 102         case wxCURSOR_LEFT_BUTTON
:      gdk_cur 
= GDK_LEFTBUTTON
; break; 
 103         case wxCURSOR_MIDDLE_BUTTON
:    gdk_cur 
= GDK_MIDDLEBUTTON
; break; 
 104         case wxCURSOR_RIGHT_BUTTON
:     gdk_cur 
= GDK_RIGHTBUTTON
; break; 
 105         case wxCURSOR_BULLSEYE
:         gdk_cur 
= GDK_TARGET
; break; 
 107         case wxCURSOR_POINT_LEFT
:       gdk_cur 
= GDK_SB_LEFT_ARROW
; break; 
 108         case wxCURSOR_POINT_RIGHT
:      gdk_cur 
= GDK_SB_RIGHT_ARROW
; break; 
 110         case wxCURSOR_DOUBLE_ARROW:     gdk_cur = GDK_DOUBLE_ARROW; break; 
 111         case wxCURSOR_CROSS_REVERSE:    gdk_cur = GDK_CROSS_REVERSE; break; 
 112         case wxCURSOR_BASED_ARROW_UP:   gdk_cur = GDK_BASED_ARROW_UP; break; 
 113         case wxCURSOR_BASED_ARROW_DOWN: gdk_cur = GDK_BASED_ARROW_DOWN; break; 
 117             wxFAIL_MSG(wxT("unsupported cursor type")); 
 118             // will use the standard one 
 122     M_CURSORDATA
->m_cursor 
= gdk_cursor_new( gdk_cur 
); 
 125 extern GtkWidget 
*wxGetRootWindow(); 
 127 wxCursor::wxCursor(const char bits
[], int width
, int  height
, 
 128                    int hotSpotX
, int hotSpotY
, 
 129                    const char maskBits
[], const wxColour 
*fg
, const wxColour 
*bg
) 
 137     if (hotSpotX 
< 0 || hotSpotX 
>= width
) 
 139     if (hotSpotY 
< 0 || hotSpotY 
>= height
) 
 142     GdkBitmap 
*data 
= gdk_bitmap_create_from_data( wxGetRootWindow()->window
, (gchar 
*) bits
, width
, height 
); 
 143     GdkBitmap 
*mask 
= gdk_bitmap_create_from_data( wxGetRootWindow()->window
, (gchar 
*) maskBits
, width
, height
); 
 145     m_refData 
= new wxCursorRefData
; 
 146     M_CURSORDATA
->m_cursor 
= gdk_cursor_new_from_pixmap( 
 147                  data
, mask
, fg
->GetColor(), bg
->GetColor(), 
 148                  hotSpotX
, hotSpotY 
); 
 150     g_object_unref (data
); 
 151     g_object_unref (mask
); 
 156 wxCursor::wxCursor( const wxImage 
& image 
) 
 158     unsigned char * rgbBits 
= image
.GetData(); 
 159     int w 
= image
.GetWidth() ; 
 160     int h 
= image
.GetHeight(); 
 161     bool bHasMask 
= image
.HasMask(); 
 162     int imagebitcount 
= (w
*h
)/8; 
 164     unsigned char * bits 
= new unsigned char [imagebitcount
]; 
 165     unsigned char * maskBits 
= new unsigned char [imagebitcount
]; 
 167     int i
, j
, i8
; unsigned char c
, cMask
; 
 168     for (i
=0; i
<imagebitcount
; i
++) 
 176             // possible overflow if we do the summation first ? 
 177             c 
= rgbBits
[(i8
+j
)*3]/3 + rgbBits
[(i8
+j
)*3+1]/3 + rgbBits
[(i8
+j
)*3+2]/3; 
 178             //if average value is > mid grey 
 180                 bits
[i
] = bits
[i
] | cMask
; 
 185     unsigned long keyMaskColor
; 
 189             r 
= image
.GetMaskRed(), 
 190             g 
= image
.GetMaskGreen(), 
 191             b 
= image
.GetMaskBlue(); 
 193         for (i
=0; i
<imagebitcount
; i
++) 
 201                 if (rgbBits
[(i8
+j
)*3] != r 
|| rgbBits
[(i8
+j
)*3+1] != g 
|| rgbBits
[(i8
+j
)*3+2] != b
) 
 202                     maskBits
[i
] = maskBits
[i
] | cMask
; 
 207         keyMaskColor 
= (r 
<< 16) | (g 
<< 8) | b
; 
 211         for (i
=0; i
<imagebitcount
; i
++) 
 214         // init it to avoid compiler warnings 
 218     // find the most frequent color(s) 
 219     wxImageHistogram histogram
; 
 220     image
.ComputeHistogram(histogram
); 
 226     long colMostFreq 
= 0; 
 227     unsigned long nMost 
= 0; 
 228     long colNextMostFreq 
= 0; 
 229     unsigned long nNext 
= 0; 
 230     for ( wxImageHistogram::iterator entry 
= histogram
.begin(); 
 231           entry 
!= histogram
.end(); 
 234         value 
= entry
->second
.value
; 
 236         if ( !bHasMask 
|| (key 
!= keyMaskColor
) ) 
 243             else if (value 
> nNext
) 
 246                 colNextMostFreq 
= key
; 
 251     wxColour fg 
= wxColour ( (unsigned char)(colMostFreq 
>> 16), 
 252                              (unsigned char)(colMostFreq 
>> 8), 
 253                              (unsigned char)(colMostFreq
) ); 
 255     wxColour bg 
= wxColour ( (unsigned char)(colNextMostFreq 
>> 16), 
 256                              (unsigned char)(colNextMostFreq 
>> 8), 
 257                              (unsigned char)(colNextMostFreq
) ); 
 259     int fg_intensity 
= fg
.Red() + fg
.Green() + fg
.Blue(); 
 260     int bg_intensity 
= bg
.Red() + bg
.Green() + bg
.Blue(); 
 262     if (bg_intensity 
> fg_intensity
) 
 273     if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
)) 
 274         hotSpotX 
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
); 
 278     if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
)) 
 279         hotSpotY 
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
); 
 283     if (hotSpotX 
< 0 || hotSpotX 
>= w
) 
 285     if (hotSpotY 
< 0 || hotSpotY 
>= h
) 
 288     GdkBitmap 
*data 
= gdk_bitmap_create_from_data(wxGetRootWindow()->window
, 
 289                                                   (gchar 
*) bits
, w
, h
); 
 290     GdkBitmap 
*mask 
= gdk_bitmap_create_from_data(wxGetRootWindow()->window
, 
 291                                                   (gchar 
*) maskBits
, w
, h
); 
 293     m_refData 
= new wxCursorRefData
; 
 294     M_CURSORDATA
->m_cursor 
= gdk_cursor_new_from_pixmap
 
 298                                 fg
.GetColor(), bg
.GetColor(), 
 302     g_object_unref (data
); 
 303     g_object_unref (mask
); 
 308 #endif // wxUSE_IMAGE 
 310 wxCursor::~wxCursor() 
 314 bool wxCursor::operator == ( const wxCursor
& cursor 
) const 
 316     return m_refData 
== cursor
.m_refData
; 
 319 bool wxCursor::operator != ( const wxCursor
& cursor 
) const 
 321     return m_refData 
!= cursor
.m_refData
; 
 324 bool wxCursor::Ok() const 
 326     return (m_refData 
!= NULL
); 
 329 GdkCursor 
*wxCursor::GetCursor() const 
 331     return M_CURSORDATA
->m_cursor
; 
 334 //----------------------------------------------------------------------------- 
 335 // busy cursor routines 
 336 //----------------------------------------------------------------------------- 
 338 extern wxCursor g_globalCursor
; 
 340 static wxCursor  gs_savedCursor
; 
 341 static int       gs_busyCount 
= 0; 
 343 const wxCursor 
&wxBusyCursor::GetStoredCursor() 
 345     return gs_savedCursor
; 
 348 const wxCursor 
wxBusyCursor::GetBusyCursor() 
 350     return wxCursor(wxCURSOR_WATCH
); 
 353 void wxEndBusyCursor() 
 355     if (--gs_busyCount 
> 0) 
 358     wxSetCursor( gs_savedCursor 
); 
 359     gs_savedCursor 
= wxNullCursor
; 
 362         wxTheApp
->ProcessIdle(); 
 365 void wxBeginBusyCursor( const wxCursor 
*WXUNUSED(cursor
) ) 
 367     if (gs_busyCount
++ > 0) 
 370     wxASSERT_MSG( !gs_savedCursor
.Ok(), 
 371                   wxT("forgot to call wxEndBusyCursor, will leak memory") ); 
 373     gs_savedCursor 
= g_globalCursor
; 
 375     wxSetCursor( wxCursor(wxCURSOR_WATCH
) ); 
 378         wxTheApp
->ProcessIdle(); 
 385     return gs_busyCount 
> 0; 
 388 void wxSetCursor( const wxCursor
& cursor 
) 
 391         wxapp_install_idle_handler(); 
 393     g_globalCursor 
= cursor
;