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" 
  30 #pragma message disable nosimpint 
  33 #include <X11/cursorfont.h> 
  35 #pragma message enable nosimpint 
  38 #include "wx/motif/private.h" 
  40 // Cursor for one display, so we can choose the correct one for 
  41 // the current display. 
  49 WX_DECLARE_LIST(wxXCursor
, wxXCursorList
); 
  50 #include "wx/listimpl.cpp" 
  51 WX_DEFINE_LIST(wxXCursorList
) 
  53 class WXDLLEXPORT wxCursorRefData
: public wxGDIRefData
 
  57     virtual ~wxCursorRefData(); 
  59     wxXCursorList m_cursors
;  // wxXCursor objects, one per display 
  60     wxStockCursor m_cursorId
; // wxWidgets standard cursor id 
  63     // There is no way to copy m_cursor so we can't implement a copy ctor 
  65     wxDECLARE_NO_COPY_CLASS(wxCursorRefData
); 
  67     friend class wxCursor
; 
  70 #define M_CURSORDATA ((wxCursorRefData *)m_refData) 
  71 #define M_CURSORHANDLERDATA ((wxCursorRefData *)bitmap->m_refData) 
  73 IMPLEMENT_DYNAMIC_CLASS(wxCursor
, wxObject
) 
  75 wxCursorRefData::wxCursorRefData() 
  77     m_cursorId 
= wxCURSOR_NONE
; 
  80 wxCursorRefData::~wxCursorRefData() 
  82     wxXCursorList::compatibility_iterator node 
= m_cursors
.GetFirst(); 
  85         wxXCursor
* c 
= node
->GetData(); 
  86         XFreeCursor((Display
*) c
->m_display
, (Cursor
) c
->m_cursor
); 
  88         node 
= node
->GetNext(); 
  97 wxCursor::wxCursor(const wxImage 
& image
) 
  99     unsigned char * rgbBits 
= image
.GetData(); 
 100     int w 
= image
.GetWidth() ; 
 101     int h 
= image
.GetHeight(); 
 102     bool bHasMask 
= image
.HasMask(); 
 103     int imagebitcount 
= (w
*h
)/8; 
 105     unsigned char * bits 
= new unsigned char [imagebitcount
]; 
 106     unsigned char * maskBits 
= new unsigned char [imagebitcount
]; 
 109     unsigned char c
, cMask
; 
 110     for (i
=0; i
<imagebitcount
; i
++) 
 115         cMask 
= 0xfe; // 11111110 
 118             // possible overflow if we do the summation first ? 
 119             c 
= (unsigned char)(rgbBits
[(i8
+j
)*3]/3 + rgbBits
[(i8
+j
)*3+1]/3 + rgbBits
[(i8
+j
)*3+2]/3); 
 120             // if average value is > mid grey 
 122                 bits
[i
] = bits
[i
] & cMask
; 
 123             cMask 
= (unsigned char)((cMask 
<< 1) | 1); 
 130             r 
= image
.GetMaskRed(), 
 131             g 
= image
.GetMaskGreen(), 
 132             b 
= image
.GetMaskBlue(); 
 134         for (i
=0; i
<imagebitcount
; i
++) 
 142                 if (rgbBits
[(i8
+j
)*3] != r 
|| rgbBits
[(i8
+j
)*3+1] != g 
|| rgbBits
[(i8
+j
)*3+2] != b
) 
 143                     maskBits
[i
] = maskBits
[i
] | cMask
; 
 144                 cMask 
= (unsigned char)(cMask 
<< 1); 
 150         for (i
=0; i
<imagebitcount
; i
++) 
 157     if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
)) 
 158         hotSpotX 
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
); 
 162     if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
)) 
 163         hotSpotY 
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
); 
 167     if (hotSpotX 
< 0 || hotSpotX 
>= w
) 
 169     if (hotSpotY 
< 0 || hotSpotY 
>= h
) 
 172     Create( (const char*)bits
, w
, h
, hotSpotX
, hotSpotY
, 
 173             (const char*)maskBits 
); 
 180 void wxCursor::Create(const char bits
[], int width
, int height
, 
 181                       int hotSpotX
, int hotSpotY
, const char maskBits
[]) 
 184         m_refData 
= new wxCursorRefData
; 
 186     Display 
*dpy 
= (Display
*) wxGetDisplay(); 
 187     int screen_num 
=  DefaultScreen (dpy
); 
 189     Pixmap pixmap 
= XCreatePixmapFromBitmapData (dpy
, 
 190                                           RootWindow (dpy
, screen_num
), 
 191                                           (char*) bits
, width
, height
, 
 194     Pixmap mask_pixmap 
= None
; 
 195     if (maskBits 
!= NULL
) 
 197         mask_pixmap 
= XCreatePixmapFromBitmapData (dpy
, 
 198                                           RootWindow (dpy
, screen_num
), 
 199                                           (char*) maskBits
, width
, height
, 
 203     Create( (WXPixmap
)pixmap
, (WXPixmap
)mask_pixmap
, hotSpotX
, hotSpotY 
); 
 205     XFreePixmap( dpy
, pixmap 
); 
 206     if (mask_pixmap 
!= None
) 
 208         XFreePixmap( dpy
, mask_pixmap 
); 
 212 void wxCursor::Create(WXPixmap pixmap
, WXPixmap mask_pixmap
, 
 213                       int hotSpotX
, int hotSpotY
) 
 216         m_refData 
= new wxCursorRefData
; 
 218     Display 
*dpy 
= (Display
*) wxGetDisplay(); 
 219     int screen_num 
=  DefaultScreen (dpy
); 
 221     XColor foreground_color
; 
 222     XColor background_color
; 
 223     foreground_color
.pixel 
= BlackPixel(dpy
, screen_num
); 
 224     background_color
.pixel 
= WhitePixel(dpy
, screen_num
); 
 225     Colormap cmap 
= (Colormap
) wxTheApp
->GetMainColormap((WXDisplay
*) dpy
); 
 226     XQueryColor(dpy
, cmap
, &foreground_color
); 
 227     XQueryColor(dpy
, cmap
, &background_color
); 
 229     Cursor cursor 
= XCreatePixmapCursor (dpy
, 
 239         wxXCursor 
*c 
= new wxXCursor
; 
 241         c
->m_cursor 
= (WXCursor
) cursor
; 
 242         c
->m_display 
= (WXDisplay
*) dpy
; 
 243         M_CURSORDATA
->m_cursors
.Append(c
); 
 247 wxCursor::wxCursor(const char bits
[], int width
, int height
, 
 248                    int hotSpotX
, int hotSpotY
, const char maskBits
[] , 
 249                    const wxColour
* WXUNUSED(fg
), const wxColour
* WXUNUSED(bg
) ) 
 251     Create(bits
, width
, height
, hotSpotX
, hotSpotY
, maskBits
); 
 254 wxCursor::wxCursor(const wxString
& name
, wxBitmapType type
, 
 255                    int hotSpotX
, int hotSpotY
) 
 257     // Must be an XBM file 
 258     if (type 
!= wxBITMAP_TYPE_XBM
) { 
 259         wxLogError("Invalid cursor bitmap type '%d'", type
); 
 263     m_refData 
= new wxCursorRefData
; 
 265     int hotX 
= -1, hotY 
= -1; 
 267     Pixmap pixmap 
= None
, mask_pixmap 
= None
; 
 269     Display 
*dpy 
= (Display
*) wxGetDisplay(); 
 270     int screen_num 
=  DefaultScreen (dpy
); 
 272     int value 
= XReadBitmapFile (dpy
, RootWindow (dpy
, screen_num
), 
 274                                  &w
, &h
, &pixmap
, &hotX
, &hotY
); 
 276     if (value 
== BitmapSuccess
) 
 278         // TODO: how do we determine whether hotX, hotY were read correctly? 
 279         if (hotX 
< 0 || hotY 
< 0) 
 284         if (hotX 
< 0 || hotY 
< 0) 
 290         Create( (WXPixmap
)pixmap
, (WXPixmap
)mask_pixmap
, hotX
, hotY 
); 
 292         XFreePixmap( dpy
, pixmap 
); 
 296 // Cursors by stock number 
 297 void wxCursor::InitFromStock(wxStockCursor id
) 
 299     m_refData 
= new wxCursorRefData
; 
 300     M_CURSORDATA
->m_cursorId 
= id
; 
 303 wxCursor::~wxCursor() 
 307 wxGDIRefData 
*wxCursor::CreateGDIRefData() const 
 309     return new wxCursorRefData
; 
 313 wxCursor::CloneGDIRefData(const wxGDIRefData 
* WXUNUSED(data
)) const 
 315     wxFAIL_MSG( wxS("Cloning cursors is not implemented in wxMotif.") ); 
 317     return new wxCursorRefData
; 
 320 // Motif-specific: create/get a cursor for the current display 
 321 WXCursor 
wxCursor::GetXCursor(WXDisplay
* display
) const 
 325     wxXCursorList::compatibility_iterator node 
= M_CURSORDATA
->m_cursors
.GetFirst(); 
 328         wxXCursor
* c 
= node
->GetData(); 
 329         if (c
->m_display 
== display
) 
 331         node 
= node
->GetNext(); 
 334     // No cursor for this display, so let's see if we're an id-type cursor. 
 336     if (M_CURSORDATA
->m_cursorId 
!= wxCURSOR_NONE
) 
 338         WXCursor cursor 
= MakeCursor(display
, M_CURSORDATA
->m_cursorId
); 
 341             wxXCursor
* c 
= new wxXCursor
; 
 342             c
->m_cursor 
= cursor
; 
 343             c
->m_display 
= display
; 
 344             M_CURSORDATA
->m_cursors
.Append(c
); 
 351     // Not an id-type cursor, so we don't know how to create it. 
 355 // Make a cursor from standard id 
 356 WXCursor 
wxCursor::MakeCursor(WXDisplay
* display
, wxStockCursor id
) const 
 358     Display
* dpy 
= (Display
*) display
; 
 359     Cursor cursor 
= (Cursor
) 0; 
 364     case wxCURSOR_CHAR
:             return (WXCursor
)cursor
; 
 366     case wxCURSOR_WAIT
:             x_cur 
= XC_watch
; break; 
 367     case wxCURSOR_CROSS
:            x_cur 
= XC_crosshair
; break; 
 368     case wxCURSOR_HAND
:             x_cur 
= XC_hand1
; break; 
 369     case wxCURSOR_BULLSEYE
:         x_cur 
= XC_target
; break; 
 370     case wxCURSOR_PENCIL
:           x_cur 
= XC_pencil
; break; 
 371     case wxCURSOR_MAGNIFIER
:        x_cur 
= XC_sizing
; break; 
 372     case wxCURSOR_IBEAM
:            x_cur 
= XC_xterm
; break; 
 373     case wxCURSOR_NO_ENTRY
:         x_cur 
= XC_pirate
; break; 
 374     case wxCURSOR_LEFT_BUTTON
:      x_cur 
= XC_leftbutton
; break; 
 375     case wxCURSOR_RIGHT_BUTTON
:     x_cur 
= XC_rightbutton
; break; 
 376     case wxCURSOR_MIDDLE_BUTTON
:    x_cur 
=  XC_middlebutton
; break; 
 377     case wxCURSOR_QUESTION_ARROW
:   x_cur 
= XC_question_arrow
; break; 
 378     case wxCURSOR_SIZING
:           x_cur 
= XC_sizing
; break; 
 379     case wxCURSOR_WATCH
:            x_cur 
= XC_watch
; break; 
 380     case wxCURSOR_SPRAYCAN
:         x_cur 
= XC_spraycan
; break; 
 381     case wxCURSOR_PAINT_BRUSH
:      x_cur 
= XC_spraycan
; break; 
 382     case wxCURSOR_SIZENWSE
: 
 383     case wxCURSOR_SIZENESW
:         x_cur 
= XC_crosshair
; break; 
 384     case wxCURSOR_SIZEWE
:           x_cur 
= XC_sb_h_double_arrow
; break; 
 385     case wxCURSOR_SIZENS
:           x_cur 
= XC_sb_v_double_arrow
; break; 
 386     case wxCURSOR_POINT_LEFT
:       x_cur 
= XC_sb_left_arrow
; break; 
 387     case wxCURSOR_POINT_RIGHT
:      x_cur 
= XC_sb_right_arrow
; break; 
 388         // (JD Huggins) added more stock cursors for X 
 389         // X-only cursors BEGIN 
 390     case wxCURSOR_CROSS_REVERSE
:    x_cur 
= XC_cross_reverse
; break; 
 391     case wxCURSOR_DOUBLE_ARROW
:     x_cur 
= XC_double_arrow
; break; 
 392     case wxCURSOR_BASED_ARROW_UP
:   x_cur 
= XC_based_arrow_up
; break; 
 393     case wxCURSOR_BASED_ARROW_DOWN
: x_cur 
= XC_based_arrow_down
; break; 
 402             XCreatePixmap (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)), 
 404         gcv
.function 
= GXxor
; 
 417         cursor 
= XCreatePixmapCursor (dpy
, 
 427     default:       x_cur 
=  XC_top_left_arrow
; break; 
 431         return (WXCursor
)cursor
; 
 433     cursor 
= XCreateFontCursor (dpy
, x_cur
); 
 434     return (WXCursor
) cursor
; 
 437 // Global cursor setting 
 438 void wxSetCursor(const wxCursor
& WXUNUSED(cursor
)) 
 440   // Nothing to do for Motif (no global cursor) 
 444 // ---------------------------------------------------------------------------- 
 446 // ---------------------------------------------------------------------------- 
 448 static int wxBusyCursorCount 
= 0; 
 452 wxXSetBusyCursor (wxWindow 
* win
, const wxCursor 
* cursor
) 
 454     Display 
*display 
= (Display
*) win
->GetXDisplay(); 
 456     Window xwin 
= (Window
) win
->GetXWindow(); 
 460     XSetWindowAttributes attrs
; 
 464         attrs
.cursor 
= (Cursor
) cursor
->GetXCursor(display
); 
 468         // Restore old cursor 
 469         if (win
->GetCursor().IsOk()) 
 470             attrs
.cursor 
= (Cursor
) win
->GetCursor().GetXCursor(display
); 
 475         XChangeWindowAttributes (display
, xwin
, CWCursor
, &attrs
); 
 479     for(wxWindowList::compatibility_iterator node 
= win
->GetChildren().GetFirst (); node
; 
 480         node 
= node
->GetNext()) 
 482         wxWindow 
*child 
= node
->GetData (); 
 483         wxXSetBusyCursor (child
, cursor
); 
 487 // Set the cursor to the busy cursor for all windows 
 488 void wxBeginBusyCursor(const wxCursor 
*cursor
) 
 491     if (wxBusyCursorCount 
== 1) 
 493         for(wxWindowList::compatibility_iterator node 
= wxTopLevelWindows
.GetFirst (); node
; 
 494             node 
= node
->GetNext()) 
 496             wxWindow 
*win 
= node
->GetData (); 
 497             wxXSetBusyCursor (win
, cursor
); 
 502 // Restore cursor to normal 
 503 void wxEndBusyCursor() 
 505     if (wxBusyCursorCount 
== 0) 
 509     if (wxBusyCursorCount 
== 0) 
 511         for(wxWindowList::compatibility_iterator node 
= wxTopLevelWindows
.GetFirst (); node
; 
 512             node 
= node
->GetNext()) 
 514             wxWindow 
*win 
= node
->GetData (); 
 515             wxXSetBusyCursor (win
, NULL
); 
 520 // true if we're between the above two calls 
 523     return (wxBusyCursorCount 
> 0);