1 /////////////////////////////////////////////////////////////////////////////
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"
15 #include "wx/cursor.h"
19 #include "wx/window.h"
25 #pragma message disable nosimpint
28 #include <X11/cursorfont.h>
30 #pragma message enable nosimpint
33 #include "wx/motif/private.h"
35 // Cursor for one display, so we can choose the correct one for
36 // the current display.
44 WX_DECLARE_LIST(wxXCursor
, wxXCursorList
);
45 #include "wx/listimpl.cpp"
46 WX_DEFINE_LIST(wxXCursorList
);
48 class WXDLLEXPORT wxCursorRefData
: public wxObjectRefData
50 friend class WXDLLEXPORT wxCursor
;
55 wxXCursorList m_cursors
; // wxXCursor objects, one per display
56 wxStockCursor m_cursorId
; // wxWidgets standard cursor id
59 #define M_CURSORDATA ((wxCursorRefData *)m_refData)
60 #define M_CURSORHANDLERDATA ((wxCursorRefData *)bitmap->m_refData)
62 IMPLEMENT_DYNAMIC_CLASS(wxCursor
, wxObject
)
64 wxCursorRefData::wxCursorRefData()
66 m_cursorId
= wxCURSOR_NONE
;
69 wxCursorRefData::~wxCursorRefData()
71 wxXCursorList::compatibility_iterator node
= m_cursors
.GetFirst();
74 wxXCursor
* c
= node
->GetData();
75 XFreeCursor((Display
*) c
->m_display
, (Cursor
) c
->m_cursor
);
77 node
= node
->GetNext();
86 wxCursor::wxCursor(const wxImage
& image
)
88 unsigned char * rgbBits
= image
.GetData();
89 int w
= image
.GetWidth() ;
90 int h
= image
.GetHeight();
91 bool bHasMask
= image
.HasMask();
92 int imagebitcount
= (w
*h
)/8;
94 unsigned char * bits
= new unsigned char [imagebitcount
];
95 unsigned char * maskBits
= new unsigned char [imagebitcount
];
97 int i
, j
, i8
; unsigned char c
, cMask
;
98 for (i
=0; i
<imagebitcount
; i
++)
103 cMask
= 0xfe; // 11111110
106 // possible overflow if we do the summation first ?
107 c
= rgbBits
[(i8
+j
)*3]/3 + rgbBits
[(i8
+j
)*3+1]/3 + rgbBits
[(i8
+j
)*3+2]/3;
108 //if average value is > mid grey
110 bits
[i
] = bits
[i
] & cMask
;
111 cMask
= (cMask
<< 1) | 1;
118 r
= image
.GetMaskRed(),
119 g
= image
.GetMaskGreen(),
120 b
= image
.GetMaskBlue();
122 for (i
=0; i
<imagebitcount
; i
++)
130 if (rgbBits
[(i8
+j
)*3] != r
|| rgbBits
[(i8
+j
)*3+1] != g
|| rgbBits
[(i8
+j
)*3+2] != b
)
131 maskBits
[i
] = maskBits
[i
] | cMask
;
132 cMask
= (cMask
<< 1);
138 for (i
=0; i
<imagebitcount
; i
++)
145 if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
))
146 hotSpotX
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
);
150 if (image
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
))
151 hotSpotY
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
);
155 if (hotSpotX
< 0 || hotSpotX
>= w
)
157 if (hotSpotY
< 0 || hotSpotY
>= h
)
160 Create( (const char*)bits
, w
, h
, hotSpotX
, hotSpotY
,
161 (const char*)maskBits
);
168 void wxCursor::Create(const char bits
[], int width
, int height
,
169 int hotSpotX
, int hotSpotY
, const char maskBits
[])
172 m_refData
= new wxCursorRefData
;
174 Display
*dpy
= (Display
*) wxGetDisplay();
175 int screen_num
= DefaultScreen (dpy
);
177 Pixmap pixmap
= XCreatePixmapFromBitmapData (dpy
,
178 RootWindow (dpy
, screen_num
),
179 (char*) bits
, width
, height
,
182 Pixmap mask_pixmap
= None
;
183 if (maskBits
!= NULL
)
185 mask_pixmap
= XCreatePixmapFromBitmapData (dpy
,
186 RootWindow (dpy
, screen_num
),
187 (char*) maskBits
, width
, height
,
191 Create( (WXPixmap
)pixmap
, (WXPixmap
)mask_pixmap
, hotSpotX
, hotSpotY
);
193 XFreePixmap( dpy
, pixmap
);
194 if (mask_pixmap
!= None
)
196 XFreePixmap( dpy
, mask_pixmap
);
200 void wxCursor::Create(WXPixmap pixmap
, WXPixmap mask_pixmap
,
201 int hotSpotX
, int hotSpotY
)
204 m_refData
= new wxCursorRefData
;
206 Display
*dpy
= (Display
*) wxGetDisplay();
207 int screen_num
= DefaultScreen (dpy
);
209 XColor foreground_color
;
210 XColor background_color
;
211 foreground_color
.pixel
= BlackPixel(dpy
, screen_num
);
212 background_color
.pixel
= WhitePixel(dpy
, screen_num
);
213 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap((WXDisplay
*) dpy
);
214 XQueryColor(dpy
, cmap
, &foreground_color
);
215 XQueryColor(dpy
, cmap
, &background_color
);
217 Cursor cursor
= XCreatePixmapCursor (dpy
,
227 wxXCursor
*c
= new wxXCursor
;
229 c
->m_cursor
= (WXCursor
) cursor
;
230 c
->m_display
= (WXDisplay
*) dpy
;
231 M_CURSORDATA
->m_cursors
.Append(c
);
235 wxCursor::wxCursor(const char bits
[], int width
, int height
,
236 int hotSpotX
, int hotSpotY
, const char maskBits
[])
238 Create(bits
, width
, height
, hotSpotX
, hotSpotY
, maskBits
);
241 wxCursor::wxCursor(const wxString
& name
, long flags
, int hotSpotX
, int hotSpotY
)
243 // Must be an XBM file
244 if (flags
!= wxBITMAP_TYPE_XBM
)
247 m_refData
= new wxCursorRefData
;
249 int hotX
= -1, hotY
= -1;
251 Pixmap pixmap
= None
, mask_pixmap
= None
;
253 Display
*dpy
= (Display
*) wxGetDisplay();
254 int screen_num
= DefaultScreen (dpy
);
256 int value
= XReadBitmapFile (dpy
, RootWindow (dpy
, screen_num
),
257 wxConstCast(name
.c_str(), char),
258 &w
, &h
, &pixmap
, &hotX
, &hotY
);
260 if (value
== BitmapSuccess
)
262 // TODO: how do we determine whether hotX, hotY were read correctly?
263 if (hotX
< 0 || hotY
< 0)
268 if (hotX
< 0 || hotY
< 0)
274 Create( (WXPixmap
)pixmap
, (WXPixmap
)mask_pixmap
, hotX
, hotY
);
276 XFreePixmap( dpy
, pixmap
);
280 // Cursors by stock number
281 wxCursor::wxCursor(wxStockCursor id
)
283 m_refData
= new wxCursorRefData
;
284 M_CURSORDATA
->m_cursorId
= id
;
287 wxCursor::~wxCursor()
291 bool wxCursor::Ok() const
293 return m_refData
!= NULL
;
296 // Motif-specific: create/get a cursor for the current display
297 WXCursor
wxCursor::GetXCursor(WXDisplay
* display
) const
301 wxXCursorList::compatibility_iterator node
= M_CURSORDATA
->m_cursors
.GetFirst();
304 wxXCursor
* c
= node
->GetData();
305 if (c
->m_display
== display
)
307 node
= node
->GetNext();
310 // No cursor for this display, so let's see if we're an id-type cursor.
312 if (M_CURSORDATA
->m_cursorId
!= wxCURSOR_NONE
)
314 WXCursor cursor
= MakeCursor(display
, M_CURSORDATA
->m_cursorId
);
317 wxXCursor
* c
= new wxXCursor
;
318 c
->m_cursor
= cursor
;
319 c
->m_display
= display
;
320 M_CURSORDATA
->m_cursors
.Append(c
);
327 // Not an id-type cursor, so we don't know how to create it.
331 // Make a cursor from standard id
332 WXCursor
wxCursor::MakeCursor(WXDisplay
* display
, wxStockCursor id
) const
334 Display
* dpy
= (Display
*) display
;
335 Cursor cursor
= (Cursor
) 0;
340 case wxCURSOR_WAIT
: x_cur
= XC_watch
; break;
341 case wxCURSOR_CROSS
: x_cur
= XC_crosshair
; break;
342 case wxCURSOR_CHAR
: return (WXCursor
)cursor
; break;
343 case wxCURSOR_HAND
: x_cur
= XC_hand1
; break;
344 case wxCURSOR_BULLSEYE
: x_cur
= XC_target
; break;
345 case wxCURSOR_PENCIL
: x_cur
= XC_pencil
; break;
346 case wxCURSOR_MAGNIFIER
: x_cur
= XC_sizing
; break;
347 case wxCURSOR_IBEAM
: x_cur
= XC_xterm
; break;
348 case wxCURSOR_NO_ENTRY
: x_cur
= XC_pirate
; break;
349 case wxCURSOR_LEFT_BUTTON
: x_cur
= XC_leftbutton
; break;
350 case wxCURSOR_RIGHT_BUTTON
: x_cur
= XC_rightbutton
; break;
351 case wxCURSOR_MIDDLE_BUTTON
: x_cur
= XC_middlebutton
; break;
352 case wxCURSOR_QUESTION_ARROW
: x_cur
= XC_question_arrow
; break;
353 case wxCURSOR_SIZING
: x_cur
= XC_sizing
; break;
354 case wxCURSOR_WATCH
: x_cur
= XC_watch
; break;
355 case wxCURSOR_SPRAYCAN
: x_cur
= XC_spraycan
; break;
356 case wxCURSOR_PAINT_BRUSH
: x_cur
= XC_spraycan
; break;
357 case wxCURSOR_SIZENWSE
:
358 case wxCURSOR_SIZENESW
: x_cur
= XC_crosshair
; break;
359 case wxCURSOR_SIZEWE
: x_cur
= XC_sb_h_double_arrow
; break;
360 case wxCURSOR_SIZENS
: x_cur
= XC_sb_v_double_arrow
; break;
361 case wxCURSOR_POINT_LEFT
: x_cur
= XC_sb_left_arrow
; break;
362 case wxCURSOR_POINT_RIGHT
: x_cur
= XC_sb_right_arrow
; break;
363 // (JD Huggins) added more stock cursors for X
364 // X-only cursors BEGIN
365 case wxCURSOR_CROSS_REVERSE
: x_cur
= XC_cross_reverse
; break;
366 case wxCURSOR_DOUBLE_ARROW
: x_cur
= XC_double_arrow
; break;
367 case wxCURSOR_BASED_ARROW_UP
: x_cur
= XC_based_arrow_up
; break;
368 case wxCURSOR_BASED_ARROW_DOWN
: x_cur
= XC_based_arrow_down
; break;
377 XCreatePixmap (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)),
379 gcv
.function
= GXxor
;
392 cursor
= XCreatePixmapCursor (dpy
,
402 default: x_cur
= XC_top_left_arrow
; break;
406 return (WXCursor
)cursor
;
408 cursor
= XCreateFontCursor (dpy
, x_cur
);
409 return (WXCursor
) cursor
;
412 // Global cursor setting
413 void wxSetCursor(const wxCursor
& WXUNUSED(cursor
))
415 // Nothing to do for Motif (no global cursor)
419 // ----------------------------------------------------------------------------
421 // ----------------------------------------------------------------------------
423 static int wxBusyCursorCount
= 0;
427 wxXSetBusyCursor (wxWindow
* win
, wxCursor
* cursor
)
429 Display
*display
= (Display
*) win
->GetXDisplay();
431 Window xwin
= (Window
) win
->GetXWindow();
435 XSetWindowAttributes attrs
;
439 attrs
.cursor
= (Cursor
) cursor
->GetXCursor(display
);
443 // Restore old cursor
444 if (win
->GetCursor().Ok())
445 attrs
.cursor
= (Cursor
) win
->GetCursor().GetXCursor(display
);
450 XChangeWindowAttributes (display
, xwin
, CWCursor
, &attrs
);
454 for(wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst (); node
;
455 node
= node
->GetNext())
457 wxWindow
*child
= node
->GetData ();
458 wxXSetBusyCursor (child
, cursor
);
462 // Set the cursor to the busy cursor for all windows
463 void wxBeginBusyCursor(wxCursor
*cursor
)
466 if (wxBusyCursorCount
== 1)
468 for(wxWindowList::compatibility_iterator node
= wxTopLevelWindows
.GetFirst (); node
;
469 node
= node
->GetNext())
471 wxWindow
*win
= node
->GetData ();
472 wxXSetBusyCursor (win
, cursor
);
477 // Restore cursor to normal
478 void wxEndBusyCursor()
480 if (wxBusyCursorCount
== 0)
484 if (wxBusyCursorCount
== 0)
486 for(wxWindowList::compatibility_iterator node
= wxTopLevelWindows
.GetFirst (); node
;
487 node
= node
->GetNext())
489 wxWindow
*win
= node
->GetData ();
490 wxXSetBusyCursor (win
, NULL
);
495 // true if we're between the above two calls
498 return (wxBusyCursorCount
> 0);