1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/motif/cursor.cpp 
   3 // Purpose:     wxCursor class 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  19 #include "wx/cursor.h" 
  24     #include "wx/window.h" 
  29 #pragma message disable nosimpint 
  32 #include <X11/cursorfont.h> 
  34 #pragma message enable nosimpint 
  37 #include "wx/motif/private.h" 
  39 // Cursor for one display, so we can choose the correct one for 
  40 // the current display. 
  48 WX_DECLARE_LIST(wxXCursor
, wxXCursorList
); 
  49 #include "wx/listimpl.cpp" 
  50 WX_DEFINE_LIST(wxXCursorList
) 
  52 class WXDLLEXPORT wxCursorRefData
: public wxGDIRefData
 
  56     virtual ~wxCursorRefData(); 
  58     wxXCursorList m_cursors
;  // wxXCursor objects, one per display 
  59     wxStockCursor m_cursorId
; // wxWidgets standard cursor id 
  61     friend class wxCursor
; 
  64 #define M_CURSORDATA ((wxCursorRefData *)m_refData) 
  65 #define M_CURSORHANDLERDATA ((wxCursorRefData *)bitmap->m_refData) 
  67 IMPLEMENT_DYNAMIC_CLASS(wxCursor
, wxObject
) 
  69 wxCursorRefData::wxCursorRefData() 
  71     m_cursorId 
= wxCURSOR_NONE
; 
  74 wxCursorRefData::~wxCursorRefData() 
  76     wxXCursorList::compatibility_iterator node 
= m_cursors
.GetFirst(); 
  79         wxXCursor
* c 
= node
->GetData(); 
  80         XFreeCursor((Display
*) c
->m_display
, (Cursor
) c
->m_cursor
); 
  82         node 
= node
->GetNext(); 
  91 wxCursor::wxCursor(const wxImage 
& image
) 
  93     unsigned char * rgbBits 
= image
.GetData(); 
  94     int w 
= image
.GetWidth() ; 
  95     int h 
= image
.GetHeight(); 
  96     bool bHasMask 
= image
.HasMask(); 
  97     int imagebitcount 
= (w
*h
)/8; 
  99     unsigned char * bits 
= new unsigned char [imagebitcount
]; 
 100     unsigned char * maskBits 
= new unsigned char [imagebitcount
]; 
 103     unsigned char c
, cMask
; 
 104     for (i
=0; i
<imagebitcount
; i
++) 
 109         cMask 
= 0xfe; // 11111110 
 112             // possible overflow if we do the summation first ? 
 113             c 
= (unsigned char)(rgbBits
[(i8
+j
)*3]/3 + rgbBits
[(i8
+j
)*3+1]/3 + rgbBits
[(i8
+j
)*3+2]/3); 
 114             // if average value is > mid grey 
 116                 bits
[i
] = bits
[i
] & cMask
; 
 117             cMask 
= (unsigned char)((cMask 
<< 1) | 1); 
 124             r 
= image
.GetMaskRed(), 
 125             g 
= image
.GetMaskGreen(), 
 126             b 
= image
.GetMaskBlue(); 
 128         for (i
=0; i
<imagebitcount
; i
++) 
 136                 if (rgbBits
[(i8
+j
)*3] != r 
|| rgbBits
[(i8
+j
)*3+1] != g 
|| rgbBits
[(i8
+j
)*3+2] != b
) 
 137                     maskBits
[i
] = maskBits
[i
] | cMask
; 
 138                 cMask 
= (unsigned char)(cMask 
<< 1); 
 144         for (i
=0; i
<imagebitcount
; i
++) 
 151     if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
)) 
 152         hotSpotX 
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
); 
 156     if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
)) 
 157         hotSpotY 
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
); 
 161     if (hotSpotX 
< 0 || hotSpotX 
>= w
) 
 163     if (hotSpotY 
< 0 || hotSpotY 
>= h
) 
 166     Create( (const char*)bits
, w
, h
, hotSpotX
, hotSpotY
, 
 167             (const char*)maskBits 
); 
 174 void wxCursor::Create(const char bits
[], int width
, int height
, 
 175                       int hotSpotX
, int hotSpotY
, const char maskBits
[]) 
 178         m_refData 
= new wxCursorRefData
; 
 180     Display 
*dpy 
= (Display
*) wxGetDisplay(); 
 181     int screen_num 
=  DefaultScreen (dpy
); 
 183     Pixmap pixmap 
= XCreatePixmapFromBitmapData (dpy
, 
 184                                           RootWindow (dpy
, screen_num
), 
 185                                           (char*) bits
, width
, height
, 
 188     Pixmap mask_pixmap 
= None
; 
 189     if (maskBits 
!= NULL
) 
 191         mask_pixmap 
= XCreatePixmapFromBitmapData (dpy
, 
 192                                           RootWindow (dpy
, screen_num
), 
 193                                           (char*) maskBits
, width
, height
, 
 197     Create( (WXPixmap
)pixmap
, (WXPixmap
)mask_pixmap
, hotSpotX
, hotSpotY 
); 
 199     XFreePixmap( dpy
, pixmap 
); 
 200     if (mask_pixmap 
!= None
) 
 202         XFreePixmap( dpy
, mask_pixmap 
); 
 206 void wxCursor::Create(WXPixmap pixmap
, WXPixmap mask_pixmap
, 
 207                       int hotSpotX
, int hotSpotY
) 
 210         m_refData 
= new wxCursorRefData
; 
 212     Display 
*dpy 
= (Display
*) wxGetDisplay(); 
 213     int screen_num 
=  DefaultScreen (dpy
); 
 215     XColor foreground_color
; 
 216     XColor background_color
; 
 217     foreground_color
.pixel 
= BlackPixel(dpy
, screen_num
); 
 218     background_color
.pixel 
= WhitePixel(dpy
, screen_num
); 
 219     Colormap cmap 
= (Colormap
) wxTheApp
->GetMainColormap((WXDisplay
*) dpy
); 
 220     XQueryColor(dpy
, cmap
, &foreground_color
); 
 221     XQueryColor(dpy
, cmap
, &background_color
); 
 223     Cursor cursor 
= XCreatePixmapCursor (dpy
, 
 233         wxXCursor 
*c 
= new wxXCursor
; 
 235         c
->m_cursor 
= (WXCursor
) cursor
; 
 236         c
->m_display 
= (WXDisplay
*) dpy
; 
 237         M_CURSORDATA
->m_cursors
.Append(c
); 
 241 wxCursor::wxCursor(const char bits
[], int width
, int height
, 
 242                    int hotSpotX
, int hotSpotY
, const char maskBits
[]) 
 244     Create(bits
, width
, height
, hotSpotX
, hotSpotY
, maskBits
); 
 247 wxCursor::wxCursor(const wxString
& name
, long flags
, int hotSpotX
, int hotSpotY
) 
 249     // Must be an XBM file 
 250     if (flags 
!= wxBITMAP_TYPE_XBM
) 
 253     m_refData 
= new wxCursorRefData
; 
 255     int hotX 
= -1, hotY 
= -1; 
 257     Pixmap pixmap 
= None
, mask_pixmap 
= None
; 
 259     Display 
*dpy 
= (Display
*) wxGetDisplay(); 
 260     int screen_num 
=  DefaultScreen (dpy
); 
 262     int value 
= XReadBitmapFile (dpy
, RootWindow (dpy
, screen_num
), 
 264                                  &w
, &h
, &pixmap
, &hotX
, &hotY
); 
 266     if (value 
== BitmapSuccess
) 
 268         // TODO: how do we determine whether hotX, hotY were read correctly? 
 269         if (hotX 
< 0 || hotY 
< 0) 
 274         if (hotX 
< 0 || hotY 
< 0) 
 280         Create( (WXPixmap
)pixmap
, (WXPixmap
)mask_pixmap
, hotX
, hotY 
); 
 282         XFreePixmap( dpy
, pixmap 
); 
 286 // Cursors by stock number 
 287 wxCursor::wxCursor(wxStockCursor id
) 
 289     m_refData 
= new wxCursorRefData
; 
 290     M_CURSORDATA
->m_cursorId 
= id
; 
 293 wxCursor::~wxCursor() 
 297 wxGDIRefData 
*wxCursor::CreateGDIRefData() const 
 299     return new wxCursorRefData
; 
 302 wxGDIRefData 
*wxCursor::CloneGDIRefData(const wxGDIRefData 
*data
) const 
 304     return new wxCursorRefData(*wx_static_cast(const wxCursorRefData 
*, data
)); 
 307 // Motif-specific: create/get a cursor for the current display 
 308 WXCursor 
wxCursor::GetXCursor(WXDisplay
* display
) const 
 312     wxXCursorList::compatibility_iterator node 
= M_CURSORDATA
->m_cursors
.GetFirst(); 
 315         wxXCursor
* c 
= node
->GetData(); 
 316         if (c
->m_display 
== display
) 
 318         node 
= node
->GetNext(); 
 321     // No cursor for this display, so let's see if we're an id-type cursor. 
 323     if (M_CURSORDATA
->m_cursorId 
!= wxCURSOR_NONE
) 
 325         WXCursor cursor 
= MakeCursor(display
, M_CURSORDATA
->m_cursorId
); 
 328             wxXCursor
* c 
= new wxXCursor
; 
 329             c
->m_cursor 
= cursor
; 
 330             c
->m_display 
= display
; 
 331             M_CURSORDATA
->m_cursors
.Append(c
); 
 338     // Not an id-type cursor, so we don't know how to create it. 
 342 // Make a cursor from standard id 
 343 WXCursor 
wxCursor::MakeCursor(WXDisplay
* display
, wxStockCursor id
) const 
 345     Display
* dpy 
= (Display
*) display
; 
 346     Cursor cursor 
= (Cursor
) 0; 
 351     case wxCURSOR_CHAR
:             return (WXCursor
)cursor
; 
 353     case wxCURSOR_WAIT
:             x_cur 
= XC_watch
; break; 
 354     case wxCURSOR_CROSS
:            x_cur 
= XC_crosshair
; break; 
 355     case wxCURSOR_HAND
:             x_cur 
= XC_hand1
; break; 
 356     case wxCURSOR_BULLSEYE
:         x_cur 
= XC_target
; break; 
 357     case wxCURSOR_PENCIL
:           x_cur 
= XC_pencil
; break; 
 358     case wxCURSOR_MAGNIFIER
:        x_cur 
= XC_sizing
; break; 
 359     case wxCURSOR_IBEAM
:            x_cur 
= XC_xterm
; break; 
 360     case wxCURSOR_NO_ENTRY
:         x_cur 
= XC_pirate
; break; 
 361     case wxCURSOR_LEFT_BUTTON
:      x_cur 
= XC_leftbutton
; break; 
 362     case wxCURSOR_RIGHT_BUTTON
:     x_cur 
= XC_rightbutton
; break; 
 363     case wxCURSOR_MIDDLE_BUTTON
:    x_cur 
=  XC_middlebutton
; break; 
 364     case wxCURSOR_QUESTION_ARROW
:   x_cur 
= XC_question_arrow
; break; 
 365     case wxCURSOR_SIZING
:           x_cur 
= XC_sizing
; break; 
 366     case wxCURSOR_WATCH
:            x_cur 
= XC_watch
; break; 
 367     case wxCURSOR_SPRAYCAN
:         x_cur 
= XC_spraycan
; break; 
 368     case wxCURSOR_PAINT_BRUSH
:      x_cur 
= XC_spraycan
; break; 
 369     case wxCURSOR_SIZENWSE
: 
 370     case wxCURSOR_SIZENESW
:         x_cur 
= XC_crosshair
; break; 
 371     case wxCURSOR_SIZEWE
:           x_cur 
= XC_sb_h_double_arrow
; break; 
 372     case wxCURSOR_SIZENS
:           x_cur 
= XC_sb_v_double_arrow
; break; 
 373     case wxCURSOR_POINT_LEFT
:       x_cur 
= XC_sb_left_arrow
; break; 
 374     case wxCURSOR_POINT_RIGHT
:      x_cur 
= XC_sb_right_arrow
; break; 
 375         // (JD Huggins) added more stock cursors for X 
 376         // X-only cursors BEGIN 
 377     case wxCURSOR_CROSS_REVERSE
:    x_cur 
= XC_cross_reverse
; break; 
 378     case wxCURSOR_DOUBLE_ARROW
:     x_cur 
= XC_double_arrow
; break; 
 379     case wxCURSOR_BASED_ARROW_UP
:   x_cur 
= XC_based_arrow_up
; break; 
 380     case wxCURSOR_BASED_ARROW_DOWN
: x_cur 
= XC_based_arrow_down
; break; 
 389             XCreatePixmap (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)), 
 391         gcv
.function 
= GXxor
; 
 404         cursor 
= XCreatePixmapCursor (dpy
, 
 414     default:       x_cur 
=  XC_top_left_arrow
; break; 
 418         return (WXCursor
)cursor
; 
 420     cursor 
= XCreateFontCursor (dpy
, x_cur
); 
 421     return (WXCursor
) cursor
; 
 424 // Global cursor setting 
 425 void wxSetCursor(const wxCursor
& WXUNUSED(cursor
)) 
 427   // Nothing to do for Motif (no global cursor) 
 431 // ---------------------------------------------------------------------------- 
 433 // ---------------------------------------------------------------------------- 
 435 static int wxBusyCursorCount 
= 0; 
 439 wxXSetBusyCursor (wxWindow 
* win
, const wxCursor 
* cursor
) 
 441     Display 
*display 
= (Display
*) win
->GetXDisplay(); 
 443     Window xwin 
= (Window
) win
->GetXWindow(); 
 447     XSetWindowAttributes attrs
; 
 451         attrs
.cursor 
= (Cursor
) cursor
->GetXCursor(display
); 
 455         // Restore old cursor 
 456         if (win
->GetCursor().Ok()) 
 457             attrs
.cursor 
= (Cursor
) win
->GetCursor().GetXCursor(display
); 
 462         XChangeWindowAttributes (display
, xwin
, CWCursor
, &attrs
); 
 466     for(wxWindowList::compatibility_iterator node 
= win
->GetChildren().GetFirst (); node
; 
 467         node 
= node
->GetNext()) 
 469         wxWindow 
*child 
= node
->GetData (); 
 470         wxXSetBusyCursor (child
, cursor
); 
 474 // Set the cursor to the busy cursor for all windows 
 475 void wxBeginBusyCursor(const wxCursor 
*cursor
) 
 478     if (wxBusyCursorCount 
== 1) 
 480         for(wxWindowList::compatibility_iterator node 
= wxTopLevelWindows
.GetFirst (); node
; 
 481             node 
= node
->GetNext()) 
 483             wxWindow 
*win 
= node
->GetData (); 
 484             wxXSetBusyCursor (win
, cursor
); 
 489 // Restore cursor to normal 
 490 void wxEndBusyCursor() 
 492     if (wxBusyCursorCount 
== 0) 
 496     if (wxBusyCursorCount 
== 0) 
 498         for(wxWindowList::compatibility_iterator node 
= wxTopLevelWindows
.GetFirst (); node
; 
 499             node 
= node
->GetNext()) 
 501             wxWindow 
*win 
= node
->GetData (); 
 502             wxXSetBusyCursor (win
, NULL
); 
 507 // true if we're between the above two calls 
 510     return (wxBusyCursorCount 
> 0);