1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/cursor.cpp
3 // Purpose: wxCursor class
4 // Author: Julian Smart
7 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
18 #include "wx/cursor.h"
23 #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
62 // There is no way to copy m_cursor so we can't implement a copy ctor
64 wxDECLARE_NO_COPY_CLASS(wxCursorRefData
);
66 friend class wxCursor
;
69 #define M_CURSORDATA ((wxCursorRefData *)m_refData)
70 #define M_CURSORHANDLERDATA ((wxCursorRefData *)bitmap->m_refData)
72 IMPLEMENT_DYNAMIC_CLASS(wxCursor
, wxObject
)
74 wxCursorRefData::wxCursorRefData()
76 m_cursorId
= wxCURSOR_NONE
;
79 wxCursorRefData::~wxCursorRefData()
81 wxXCursorList::compatibility_iterator node
= m_cursors
.GetFirst();
84 wxXCursor
* c
= node
->GetData();
85 XFreeCursor((Display
*) c
->m_display
, (Cursor
) c
->m_cursor
);
87 node
= node
->GetNext();
96 wxCursor::wxCursor(const wxImage
& image
)
98 unsigned char * rgbBits
= image
.GetData();
99 int w
= image
.GetWidth() ;
100 int h
= image
.GetHeight();
101 bool bHasMask
= image
.HasMask();
102 int imagebitcount
= (w
*h
)/8;
104 unsigned char * bits
= new unsigned char [imagebitcount
];
105 unsigned char * maskBits
= new unsigned char [imagebitcount
];
108 unsigned char c
, cMask
;
109 for (i
=0; i
<imagebitcount
; i
++)
114 cMask
= 0xfe; // 11111110
117 // possible overflow if we do the summation first ?
118 c
= (unsigned char)(rgbBits
[(i8
+j
)*3]/3 + rgbBits
[(i8
+j
)*3+1]/3 + rgbBits
[(i8
+j
)*3+2]/3);
119 // if average value is > mid grey
121 bits
[i
] = bits
[i
] & cMask
;
122 cMask
= (unsigned char)((cMask
<< 1) | 1);
129 r
= image
.GetMaskRed(),
130 g
= image
.GetMaskGreen(),
131 b
= image
.GetMaskBlue();
133 for (i
=0; i
<imagebitcount
; i
++)
141 if (rgbBits
[(i8
+j
)*3] != r
|| rgbBits
[(i8
+j
)*3+1] != g
|| rgbBits
[(i8
+j
)*3+2] != b
)
142 maskBits
[i
] = maskBits
[i
] | cMask
;
143 cMask
= (unsigned char)(cMask
<< 1);
149 for (i
=0; i
<imagebitcount
; i
++)
156 if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
))
157 hotSpotX
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
);
161 if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
))
162 hotSpotY
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
);
166 if (hotSpotX
< 0 || hotSpotX
>= w
)
168 if (hotSpotY
< 0 || hotSpotY
>= h
)
171 Create( (const char*)bits
, w
, h
, hotSpotX
, hotSpotY
,
172 (const char*)maskBits
);
179 void wxCursor::Create(const char bits
[], int width
, int height
,
180 int hotSpotX
, int hotSpotY
, const char maskBits
[])
183 m_refData
= new wxCursorRefData
;
185 Display
*dpy
= (Display
*) wxGetDisplay();
186 int screen_num
= DefaultScreen (dpy
);
188 Pixmap pixmap
= XCreatePixmapFromBitmapData (dpy
,
189 RootWindow (dpy
, screen_num
),
190 (char*) bits
, width
, height
,
193 Pixmap mask_pixmap
= None
;
194 if (maskBits
!= NULL
)
196 mask_pixmap
= XCreatePixmapFromBitmapData (dpy
,
197 RootWindow (dpy
, screen_num
),
198 (char*) maskBits
, width
, height
,
202 Create( (WXPixmap
)pixmap
, (WXPixmap
)mask_pixmap
, hotSpotX
, hotSpotY
);
204 XFreePixmap( dpy
, pixmap
);
205 if (mask_pixmap
!= None
)
207 XFreePixmap( dpy
, mask_pixmap
);
211 void wxCursor::Create(WXPixmap pixmap
, WXPixmap mask_pixmap
,
212 int hotSpotX
, int hotSpotY
)
215 m_refData
= new wxCursorRefData
;
217 Display
*dpy
= (Display
*) wxGetDisplay();
218 int screen_num
= DefaultScreen (dpy
);
220 XColor foreground_color
;
221 XColor background_color
;
222 foreground_color
.pixel
= BlackPixel(dpy
, screen_num
);
223 background_color
.pixel
= WhitePixel(dpy
, screen_num
);
224 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap((WXDisplay
*) dpy
);
225 XQueryColor(dpy
, cmap
, &foreground_color
);
226 XQueryColor(dpy
, cmap
, &background_color
);
228 Cursor cursor
= XCreatePixmapCursor (dpy
,
238 wxXCursor
*c
= new wxXCursor
;
240 c
->m_cursor
= (WXCursor
) cursor
;
241 c
->m_display
= (WXDisplay
*) dpy
;
242 M_CURSORDATA
->m_cursors
.Append(c
);
246 wxCursor::wxCursor(const char bits
[], int width
, int height
,
247 int hotSpotX
, int hotSpotY
, const char maskBits
[] ,
248 const wxColour
* WXUNUSED(fg
), const wxColour
* WXUNUSED(bg
) )
250 Create(bits
, width
, height
, hotSpotX
, hotSpotY
, maskBits
);
253 wxCursor::wxCursor(const wxString
& name
, wxBitmapType type
,
254 int hotSpotX
, int hotSpotY
)
256 // Must be an XBM file
257 if (type
!= wxBITMAP_TYPE_XBM
) {
258 wxLogError("Invalid cursor bitmap type '%d'", type
);
262 m_refData
= new wxCursorRefData
;
264 int hotX
= -1, hotY
= -1;
266 Pixmap pixmap
= None
, mask_pixmap
= None
;
268 Display
*dpy
= (Display
*) wxGetDisplay();
269 int screen_num
= DefaultScreen (dpy
);
271 int value
= XReadBitmapFile (dpy
, RootWindow (dpy
, screen_num
),
273 &w
, &h
, &pixmap
, &hotX
, &hotY
);
275 if (value
== BitmapSuccess
)
277 // TODO: how do we determine whether hotX, hotY were read correctly?
278 if (hotX
< 0 || hotY
< 0)
283 if (hotX
< 0 || hotY
< 0)
289 Create( (WXPixmap
)pixmap
, (WXPixmap
)mask_pixmap
, hotX
, hotY
);
291 XFreePixmap( dpy
, pixmap
);
295 // Cursors by stock number
296 void wxCursor::InitFromStock(wxStockCursor id
)
298 m_refData
= new wxCursorRefData
;
299 M_CURSORDATA
->m_cursorId
= id
;
302 wxCursor::~wxCursor()
306 wxGDIRefData
*wxCursor::CreateGDIRefData() const
308 return new wxCursorRefData
;
312 wxCursor::CloneGDIRefData(const wxGDIRefData
* WXUNUSED(data
)) const
314 wxFAIL_MSG( wxS("Cloning cursors is not implemented in wxMotif.") );
316 return new wxCursorRefData
;
319 // Motif-specific: create/get a cursor for the current display
320 WXCursor
wxCursor::GetXCursor(WXDisplay
* display
) const
324 wxXCursorList::compatibility_iterator node
= M_CURSORDATA
->m_cursors
.GetFirst();
327 wxXCursor
* c
= node
->GetData();
328 if (c
->m_display
== display
)
330 node
= node
->GetNext();
333 // No cursor for this display, so let's see if we're an id-type cursor.
335 if (M_CURSORDATA
->m_cursorId
!= wxCURSOR_NONE
)
337 WXCursor cursor
= MakeCursor(display
, M_CURSORDATA
->m_cursorId
);
340 wxXCursor
* c
= new wxXCursor
;
341 c
->m_cursor
= cursor
;
342 c
->m_display
= display
;
343 M_CURSORDATA
->m_cursors
.Append(c
);
350 // Not an id-type cursor, so we don't know how to create it.
354 // Make a cursor from standard id
355 WXCursor
wxCursor::MakeCursor(WXDisplay
* display
, wxStockCursor id
) const
357 Display
* dpy
= (Display
*) display
;
358 Cursor cursor
= (Cursor
) 0;
363 case wxCURSOR_CHAR
: return (WXCursor
)cursor
;
365 case wxCURSOR_WAIT
: x_cur
= XC_watch
; break;
366 case wxCURSOR_CROSS
: x_cur
= XC_crosshair
; break;
367 case wxCURSOR_HAND
: x_cur
= XC_hand1
; break;
368 case wxCURSOR_BULLSEYE
: x_cur
= XC_target
; break;
369 case wxCURSOR_PENCIL
: x_cur
= XC_pencil
; break;
370 case wxCURSOR_MAGNIFIER
: x_cur
= XC_sizing
; break;
371 case wxCURSOR_IBEAM
: x_cur
= XC_xterm
; break;
372 case wxCURSOR_NO_ENTRY
: x_cur
= XC_pirate
; break;
373 case wxCURSOR_LEFT_BUTTON
: x_cur
= XC_leftbutton
; break;
374 case wxCURSOR_RIGHT_BUTTON
: x_cur
= XC_rightbutton
; break;
375 case wxCURSOR_MIDDLE_BUTTON
: x_cur
= XC_middlebutton
; break;
376 case wxCURSOR_QUESTION_ARROW
: x_cur
= XC_question_arrow
; break;
377 case wxCURSOR_SIZING
: x_cur
= XC_sizing
; break;
378 case wxCURSOR_WATCH
: x_cur
= XC_watch
; break;
379 case wxCURSOR_SPRAYCAN
: x_cur
= XC_spraycan
; break;
380 case wxCURSOR_PAINT_BRUSH
: x_cur
= XC_spraycan
; break;
381 case wxCURSOR_SIZENWSE
:
382 case wxCURSOR_SIZENESW
: x_cur
= XC_crosshair
; break;
383 case wxCURSOR_SIZEWE
: x_cur
= XC_sb_h_double_arrow
; break;
384 case wxCURSOR_SIZENS
: x_cur
= XC_sb_v_double_arrow
; break;
385 case wxCURSOR_POINT_LEFT
: x_cur
= XC_sb_left_arrow
; break;
386 case wxCURSOR_POINT_RIGHT
: x_cur
= XC_sb_right_arrow
; break;
387 // (JD Huggins) added more stock cursors for X
388 // X-only cursors BEGIN
389 case wxCURSOR_CROSS_REVERSE
: x_cur
= XC_cross_reverse
; break;
390 case wxCURSOR_DOUBLE_ARROW
: x_cur
= XC_double_arrow
; break;
391 case wxCURSOR_BASED_ARROW_UP
: x_cur
= XC_based_arrow_up
; break;
392 case wxCURSOR_BASED_ARROW_DOWN
: x_cur
= XC_based_arrow_down
; break;
401 XCreatePixmap (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)),
403 gcv
.function
= GXxor
;
416 cursor
= XCreatePixmapCursor (dpy
,
426 default: x_cur
= XC_top_left_arrow
; break;
430 return (WXCursor
)cursor
;
432 cursor
= XCreateFontCursor (dpy
, x_cur
);
433 return (WXCursor
) cursor
;
436 // Global cursor setting
437 void wxSetCursor(const wxCursor
& WXUNUSED(cursor
))
439 // Nothing to do for Motif (no global cursor)
443 // ----------------------------------------------------------------------------
445 // ----------------------------------------------------------------------------
447 static int wxBusyCursorCount
= 0;
451 wxXSetBusyCursor (wxWindow
* win
, const wxCursor
* cursor
)
453 Display
*display
= (Display
*) win
->GetXDisplay();
455 Window xwin
= (Window
) win
->GetXWindow();
459 XSetWindowAttributes attrs
;
463 attrs
.cursor
= (Cursor
) cursor
->GetXCursor(display
);
467 // Restore old cursor
468 if (win
->GetCursor().IsOk())
469 attrs
.cursor
= (Cursor
) win
->GetCursor().GetXCursor(display
);
474 XChangeWindowAttributes (display
, xwin
, CWCursor
, &attrs
);
478 for(wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst (); node
;
479 node
= node
->GetNext())
481 wxWindow
*child
= node
->GetData ();
482 wxXSetBusyCursor (child
, cursor
);
486 // Set the cursor to the busy cursor for all windows
487 void wxBeginBusyCursor(const wxCursor
*cursor
)
490 if (wxBusyCursorCount
== 1)
492 for(wxWindowList::compatibility_iterator node
= wxTopLevelWindows
.GetFirst (); node
;
493 node
= node
->GetNext())
495 wxWindow
*win
= node
->GetData ();
496 wxXSetBusyCursor (win
, cursor
);
501 // Restore cursor to normal
502 void wxEndBusyCursor()
504 if (wxBusyCursorCount
== 0)
508 if (wxBusyCursorCount
== 0)
510 for(wxWindowList::compatibility_iterator node
= wxTopLevelWindows
.GetFirst (); node
;
511 node
= node
->GetNext())
513 wxWindow
*win
= node
->GetData ();
514 wxXSetBusyCursor (win
, NULL
);
519 // true if we're between the above two calls
522 return (wxBusyCursorCount
> 0);