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" 
  21 #include "wx/gtk/private.h" //for idle stuff 
  26 //----------------------------------------------------------------------------- 
  28 //----------------------------------------------------------------------------- 
  30 class wxCursorRefData
: public wxObjectRefData
 
  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 ((wxCursorRefData *)m_refData) 
  54 IMPLEMENT_DYNAMIC_CLASS(wxCursor
,wxObject
) 
  61 wxCursor::wxCursor( int cursorId 
) 
  63     m_refData 
= new wxCursorRefData(); 
  65     GdkCursorType gdk_cur 
= GDK_LEFT_PTR
; 
  70                 static const gchar bits
[] = { 0 }; 
  71                 static /* const -- not in GTK1 */ GdkColor color 
= { 0, 0, 0, 0 }; 
  73                 GdkPixmap 
*pixmap 
= gdk_bitmap_create_from_data(NULL
, bits
, 1, 1); 
  74                 M_CURSORDATA
->m_cursor 
= gdk_cursor_new_from_pixmap(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 (G_OBJECT (data
)); 
 152     g_object_unref (G_OBJECT (mask
)); 
 157 wxCursor::wxCursor( const wxImage 
& image 
) 
 159     unsigned char * rgbBits 
= image
.GetData(); 
 160     int w 
= image
.GetWidth() ; 
 161     int h 
= image
.GetHeight(); 
 162     bool bHasMask 
= image
.HasMask(); 
 163     int imagebitcount 
= (w
*h
)/8; 
 165     unsigned char * bits 
= new unsigned char [imagebitcount
]; 
 166     unsigned char * maskBits 
= new unsigned char [imagebitcount
]; 
 168     int i
, j
, i8
; unsigned char c
, cMask
; 
 169     for (i
=0; i
<imagebitcount
; i
++) 
 177             // possible overflow if we do the summation first ? 
 178             c 
= rgbBits
[(i8
+j
)*3]/3 + rgbBits
[(i8
+j
)*3+1]/3 + rgbBits
[(i8
+j
)*3+2]/3; 
 179             //if average value is > mid grey 
 181                 bits
[i
] = bits
[i
] | cMask
; 
 186     unsigned long keyMaskColor
; 
 190             r 
= image
.GetMaskRed(), 
 191             g 
= image
.GetMaskGreen(), 
 192             b 
= image
.GetMaskBlue(); 
 194         for (i
=0; i
<imagebitcount
; i
++) 
 202                 if (rgbBits
[(i8
+j
)*3] != r 
|| rgbBits
[(i8
+j
)*3+1] != g 
|| rgbBits
[(i8
+j
)*3+2] != b
) 
 203                     maskBits
[i
] = maskBits
[i
] | cMask
; 
 208         keyMaskColor 
= (r 
<< 16) | (g 
<< 8) | b
; 
 212         for (i
=0; i
<imagebitcount
; i
++) 
 215         // init it to avoid compiler warnings 
 219     // find the most frequent color(s) 
 220     wxImageHistogram histogram
; 
 221     image
.ComputeHistogram(histogram
); 
 227     long colMostFreq 
= 0; 
 228     unsigned long nMost 
= 0; 
 229     long colNextMostFreq 
= 0; 
 230     unsigned long nNext 
= 0; 
 231     for ( wxImageHistogram::iterator entry 
= histogram
.begin(); 
 232           entry 
!= histogram
.end(); 
 235         value 
= entry
->second
.value
; 
 237         if ( !bHasMask 
|| (key 
!= keyMaskColor
) ) 
 244             else if (value 
> nNext
) 
 247                 colNextMostFreq 
= key
; 
 252     wxColour fg 
= wxColour ( (unsigned char)(colMostFreq 
>> 16), 
 253                              (unsigned char)(colMostFreq 
>> 8), 
 254                              (unsigned char)(colMostFreq
) ); 
 256     wxColour bg 
= wxColour ( (unsigned char)(colNextMostFreq 
>> 16), 
 257                              (unsigned char)(colNextMostFreq 
>> 8), 
 258                              (unsigned char)(colNextMostFreq
) ); 
 260     int fg_intensity 
= fg
.Red() + fg
.Green() + fg
.Blue(); 
 261     int bg_intensity 
= bg
.Red() + bg
.Green() + bg
.Blue(); 
 263     if (bg_intensity 
> fg_intensity
) 
 274     if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
)) 
 275         hotSpotX 
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
); 
 279     if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
)) 
 280         hotSpotY 
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
); 
 284     if (hotSpotX 
< 0 || hotSpotX 
>= w
) 
 286     if (hotSpotY 
< 0 || hotSpotY 
>= h
) 
 289     GdkBitmap 
*data 
= gdk_bitmap_create_from_data(wxGetRootWindow()->window
, 
 290                                                   (gchar 
*) bits
, w
, h
); 
 291     GdkBitmap 
*mask 
= gdk_bitmap_create_from_data(wxGetRootWindow()->window
, 
 292                                                   (gchar 
*) maskBits
, w
, h
); 
 294     m_refData 
= new wxCursorRefData
; 
 295     M_CURSORDATA
->m_cursor 
= gdk_cursor_new_from_pixmap
 
 299                                 fg
.GetColor(), bg
.GetColor(), 
 303     g_object_unref (G_OBJECT (data
)); 
 304     g_object_unref (G_OBJECT (mask
)); 
 309 #endif // wxUSE_IMAGE 
 311 wxCursor::~wxCursor() 
 315 bool wxCursor::operator == ( const wxCursor
& cursor 
) const 
 317     return m_refData 
== cursor
.m_refData
; 
 320 bool wxCursor::operator != ( const wxCursor
& cursor 
) const 
 322     return m_refData 
!= cursor
.m_refData
; 
 325 bool wxCursor::Ok() const 
 327     return (m_refData 
!= NULL
); 
 330 GdkCursor 
*wxCursor::GetCursor() const 
 332     return M_CURSORDATA
->m_cursor
; 
 335 //----------------------------------------------------------------------------- 
 336 // busy cursor routines 
 337 //----------------------------------------------------------------------------- 
 339 extern wxCursor g_globalCursor
; 
 341 static wxCursor  gs_savedCursor
; 
 342 static int       gs_busyCount 
= 0; 
 344 const wxCursor 
&wxBusyCursor::GetStoredCursor() 
 346     return gs_savedCursor
; 
 349 const wxCursor 
wxBusyCursor::GetBusyCursor() 
 351     return wxCursor(wxCURSOR_WATCH
); 
 354 void wxEndBusyCursor() 
 356     if (--gs_busyCount 
> 0) 
 359     wxSetCursor( gs_savedCursor 
); 
 360     gs_savedCursor 
= wxNullCursor
; 
 363         wxTheApp
->ProcessIdle(); 
 366 void wxBeginBusyCursor( const wxCursor 
*WXUNUSED(cursor
) ) 
 368     if (gs_busyCount
++ > 0) 
 371     wxASSERT_MSG( !gs_savedCursor
.Ok(), 
 372                   wxT("forgot to call wxEndBusyCursor, will leak memory") ); 
 374     gs_savedCursor 
= g_globalCursor
; 
 376     wxSetCursor( wxCursor(wxCURSOR_WATCH
) ); 
 379         wxTheApp
->ProcessIdle(); 
 386     return gs_busyCount 
> 0; 
 389 void wxSetCursor( const wxCursor
& cursor 
) 
 392         wxapp_install_idle_handler(); 
 394     g_globalCursor 
= cursor
;