1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxCursor class
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "cursor.h"
16 #include "wx/cursor.h"
20 #include "wx/window.h"
26 #pragma message disable nosimpint
29 #include <X11/cursorfont.h>
31 #pragma message enable nosimpint
34 #include "wx/motif/private.h"
36 // Cursor for one display, so we can choose the correct one for
37 // the current display.
45 WX_DECLARE_LIST(wxXCursor
, wxXCursorList
);
46 #include "wx/listimpl.cpp"
47 WX_DEFINE_LIST(wxXCursorList
);
49 class WXDLLEXPORT wxCursorRefData
: public wxObjectRefData
51 friend class WXDLLEXPORT wxCursor
;
56 wxXCursorList m_cursors
; // wxXCursor objects, one per display
57 wxStockCursor m_cursorId
; // wxWindows standard cursor id
60 #define M_CURSORDATA ((wxCursorRefData *)m_refData)
61 #define M_CURSORHANDLERDATA ((wxCursorRefData *)bitmap->m_refData)
63 IMPLEMENT_DYNAMIC_CLASS(wxCursor
, wxObject
)
65 wxCursorRefData::wxCursorRefData()
67 m_cursorId
= wxCURSOR_NONE
;
70 wxCursorRefData::~wxCursorRefData()
72 wxXCursorList::Node
* node
= m_cursors
.GetFirst();
75 wxXCursor
* c
= node
->GetData();
76 XFreeCursor((Display
*) c
->m_display
, (Cursor
) c
->m_cursor
);
78 node
= node
->GetNext();
87 wxCursor::wxCursor(const wxImage
& image
)
89 unsigned char * rgbBits
= image
.GetData();
90 int w
= image
.GetWidth() ;
91 int h
= image
.GetHeight();
92 bool bHasMask
= image
.HasMask();
93 int imagebitcount
= (w
*h
)/8;
95 unsigned char * bits
= new unsigned char [imagebitcount
];
96 unsigned char * maskBits
= new unsigned char [imagebitcount
];
98 int i
, j
, i8
; unsigned char c
, cMask
;
99 for (i
=0; i
<imagebitcount
; i
++)
107 // possible overflow if we do the summation first ?
108 c
= rgbBits
[(i8
+j
)*3]/3 + rgbBits
[(i8
+j
)*3+1]/3 + rgbBits
[(i8
+j
)*3+2]/3;
109 //if average value is > mid grey
111 bits
[i
] = bits
[i
] | cMask
;
119 r
= image
.GetMaskRed(),
120 g
= image
.GetMaskGreen(),
121 b
= image
.GetMaskBlue();
123 for (i
=0; i
<imagebitcount
; i
++)
131 if (rgbBits
[(i8
+j
)*3] != r
|| rgbBits
[(i8
+j
)*3+1] != g
|| rgbBits
[(i8
+j
)*3+2] != b
)
132 maskBits
[i
] = maskBits
[i
] | cMask
;
139 for (i
=0; i
<imagebitcount
; i
++)
146 if (image
.HasOption(wxCUR_HOTSPOT_X
))
147 hotSpotX
= image
.GetOptionInt(wxCUR_HOTSPOT_X
);
151 if (image
.HasOption(wxCUR_HOTSPOT_Y
))
152 hotSpotY
= image
.GetOptionInt(wxCUR_HOTSPOT_Y
);
156 if (hotSpotX
< 0 || hotSpotX
>= w
)
158 if (hotSpotY
< 0 || hotSpotY
>= h
)
161 m_refData
= new wxCursorRefData
;
163 Display
*dpy
= (Display
*) wxGetDisplay();
164 int screen_num
= DefaultScreen (dpy
);
166 Pixmap pixmap
= XCreatePixmapFromBitmapData (dpy
,
167 RootWindow (dpy
, DefaultScreen(dpy
)),
171 Pixmap mask_pixmap
= None
;
172 if (maskBits
!= NULL
)
174 mask_pixmap
= XCreatePixmapFromBitmapData (dpy
,
175 RootWindow (dpy
, DefaultScreen(dpy
)),
176 (char*) maskBits
, w
, h
,
180 XColor foreground_color
;
181 XColor background_color
;
182 foreground_color
.pixel
= BlackPixel(dpy
, screen_num
);
183 background_color
.pixel
= WhitePixel(dpy
, screen_num
);
184 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap((WXDisplay
*) dpy
);
185 XQueryColor(dpy
, cmap
, &foreground_color
);
186 XQueryColor(dpy
, cmap
, &background_color
);
188 Cursor cursor
= XCreatePixmapCursor (dpy
,
196 XFreePixmap( dpy
, pixmap
);
197 if (mask_pixmap
!= None
)
199 XFreePixmap( dpy
, mask_pixmap
);
204 wxXCursor
*c
= new wxXCursor
;
206 c
->m_cursor
= (WXCursor
) cursor
;
207 c
->m_display
= (WXDisplay
*) dpy
;
208 M_CURSORDATA
->m_cursors
.Append(c
);
213 wxCursor::wxCursor(const char bits
[], int width
, int height
,
214 int hotSpotX
, int hotSpotY
, const char maskBits
[])
216 m_refData
= new wxCursorRefData
;
218 Display
*dpy
= (Display
*) wxGetDisplay();
219 int screen_num
= DefaultScreen (dpy
);
221 Pixmap pixmap
= XCreatePixmapFromBitmapData (dpy
,
222 RootWindow (dpy
, DefaultScreen(dpy
)),
223 (char*) bits
, width
, height
,
226 Pixmap mask_pixmap
= None
;
227 if (maskBits
!= NULL
)
229 mask_pixmap
= XCreatePixmapFromBitmapData (dpy
,
230 RootWindow (dpy
, DefaultScreen(dpy
)),
231 (char*) maskBits
, width
, height
,
235 XColor foreground_color
;
236 XColor background_color
;
237 foreground_color
.pixel
= BlackPixel(dpy
, screen_num
);
238 background_color
.pixel
= WhitePixel(dpy
, screen_num
);
239 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap((WXDisplay
*) dpy
);
240 XQueryColor(dpy
, cmap
, &foreground_color
);
241 XQueryColor(dpy
, cmap
, &background_color
);
243 Cursor cursor
= XCreatePixmapCursor (dpy
,
251 XFreePixmap( dpy
, pixmap
);
252 if (mask_pixmap
!= None
)
254 XFreePixmap( dpy
, mask_pixmap
);
259 wxXCursor
*c
= new wxXCursor
;
261 c
->m_cursor
= (WXCursor
) cursor
;
262 c
->m_display
= (WXDisplay
*) dpy
;
263 M_CURSORDATA
->m_cursors
.Append(c
);
267 wxCursor::wxCursor(const wxString
& name
, long flags
, int hotSpotX
, int hotSpotY
)
269 // Must be an XBM file
270 if (flags
!= wxBITMAP_TYPE_XBM
)
273 m_refData
= new wxCursorRefData
;
275 int hotX
= -1, hotY
= -1;
279 Display
*dpy
= (Display
*) wxGetDisplay();
280 int screen_num
= DefaultScreen (dpy
);
282 int value
= XReadBitmapFile (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)),
283 wxConstCast(name
.c_str(), char),
284 &w
, &h
, &pixmap
, &hotX
, &hotY
);
286 if ((value
== BitmapFileInvalid
) ||
287 (value
== BitmapOpenFailed
) ||
288 (value
== BitmapNoMemory
))
293 XColor foreground_color
;
294 XColor background_color
;
295 foreground_color
.pixel
= BlackPixel(dpy
, screen_num
);
296 background_color
.pixel
= WhitePixel(dpy
, screen_num
);
297 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap((WXDisplay
*) dpy
);
298 XQueryColor(dpy
, cmap
, &foreground_color
);
299 XQueryColor(dpy
, cmap
, &background_color
);
301 // TODO: how do we determine whether hotX, hotY were read correctly?
302 if (hotX
< 0 || hotY
< 0)
307 if (hotX
< 0 || hotY
< 0)
313 Pixmap mask_pixmap
= None
;
314 Cursor cursor
= XCreatePixmapCursor (dpy
,
322 XFreePixmap( dpy
, pixmap
);
325 wxXCursor
*c
= new wxXCursor
;
327 c
->m_cursor
= (WXCursor
) cursor
;
328 c
->m_display
= (WXDisplay
*) dpy
;
329 M_CURSORDATA
->m_cursors
.Append(c
);
335 // Cursors by stock number
336 wxCursor::wxCursor(wxStockCursor id
)
338 m_refData
= new wxCursorRefData
;
339 M_CURSORDATA
->m_cursorId
= id
;
342 wxCursor::~wxCursor()
346 bool wxCursor::Ok() const
348 return m_refData
!= NULL
;
351 // Motif-specific: create/get a cursor for the current display
352 WXCursor
wxCursor::GetXCursor(WXDisplay
* display
)
356 wxXCursorList::Node
* node
= M_CURSORDATA
->m_cursors
.GetFirst();
359 wxXCursor
* c
= node
->GetData();
360 if (c
->m_display
== display
)
362 node
= node
->GetNext();
365 // No cursor for this display, so let's see if we're an id-type cursor.
367 if (M_CURSORDATA
->m_cursorId
!= wxCURSOR_NONE
)
369 WXCursor cursor
= MakeCursor(display
, M_CURSORDATA
->m_cursorId
);
372 wxXCursor
* c
= new wxXCursor
;
373 c
->m_cursor
= cursor
;
374 c
->m_display
= display
;
375 M_CURSORDATA
->m_cursors
.Append(c
);
382 // Not an id-type cursor, so we don't know how to create it.
386 // Make a cursor from standard id
387 WXCursor
wxCursor::MakeCursor(WXDisplay
* display
, wxStockCursor id
)
389 Display
* dpy
= (Display
*) display
;
390 Cursor cursor
= (Cursor
) 0;
395 case wxCURSOR_WAIT
: x_cur
= XC_watch
; break;
396 case wxCURSOR_CROSS
: x_cur
= XC_crosshair
; break;
397 case wxCURSOR_CHAR
: return (WXCursor
)cursor
; break;
398 case wxCURSOR_HAND
: x_cur
= XC_hand1
; break;
399 case wxCURSOR_BULLSEYE
: x_cur
= XC_target
; break;
400 case wxCURSOR_PENCIL
: x_cur
= XC_pencil
; break;
401 case wxCURSOR_MAGNIFIER
: x_cur
= XC_sizing
; break;
402 case wxCURSOR_IBEAM
: x_cur
= XC_xterm
; break;
403 case wxCURSOR_NO_ENTRY
: x_cur
= XC_pirate
; break;
404 case wxCURSOR_LEFT_BUTTON
: x_cur
= XC_leftbutton
; break;
405 case wxCURSOR_RIGHT_BUTTON
: x_cur
= XC_rightbutton
; break;
406 case wxCURSOR_MIDDLE_BUTTON
: x_cur
= XC_middlebutton
; break;
407 case wxCURSOR_QUESTION_ARROW
: x_cur
= XC_question_arrow
; break;
408 case wxCURSOR_SIZING
: x_cur
= XC_sizing
; break;
409 case wxCURSOR_WATCH
: x_cur
= XC_watch
; break;
410 case wxCURSOR_SPRAYCAN
: x_cur
= XC_spraycan
; break;
411 case wxCURSOR_PAINT_BRUSH
: x_cur
= XC_spraycan
; break;
412 case wxCURSOR_SIZENWSE
:
413 case wxCURSOR_SIZENESW
: x_cur
= XC_crosshair
; break;
414 case wxCURSOR_SIZEWE
: x_cur
= XC_sb_h_double_arrow
; break;
415 case wxCURSOR_SIZENS
: x_cur
= XC_sb_v_double_arrow
; break;
416 case wxCURSOR_POINT_LEFT
: x_cur
= XC_sb_left_arrow
; break;
417 case wxCURSOR_POINT_RIGHT
: x_cur
= XC_sb_right_arrow
; break;
418 // (JD Huggins) added more stock cursors for X
419 // X-only cursors BEGIN
420 case wxCURSOR_CROSS_REVERSE
: x_cur
= XC_cross_reverse
; break;
421 case wxCURSOR_DOUBLE_ARROW
: x_cur
= XC_double_arrow
; break;
422 case wxCURSOR_BASED_ARROW_UP
: x_cur
= XC_based_arrow_up
; break;
423 case wxCURSOR_BASED_ARROW_DOWN
: x_cur
= XC_based_arrow_down
; break;
432 XCreatePixmap (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)),
434 gcv
.function
= GXxor
;
447 cursor
= XCreatePixmapCursor (dpy
,
457 default: x_cur
= XC_top_left_arrow
; break;
461 return (WXCursor
)cursor
;
463 cursor
= XCreateFontCursor (dpy
, x_cur
);
464 return (WXCursor
) cursor
;
467 // Global cursor setting
468 void wxSetCursor(const wxCursor
& WXUNUSED(cursor
))
470 // Nothing to do for Motif (no global cursor)
474 // ----------------------------------------------------------------------------
476 // ----------------------------------------------------------------------------
478 static int wxBusyCursorCount
= 0;
482 wxXSetBusyCursor (wxWindow
* win
, wxCursor
* cursor
)
484 Display
*display
= (Display
*) win
->GetXDisplay();
486 Window xwin
= (Window
) win
->GetXWindow();
490 XSetWindowAttributes attrs
;
494 attrs
.cursor
= (Cursor
) cursor
->GetXCursor(display
);
498 // Restore old cursor
499 if (win
->GetCursor().Ok())
500 attrs
.cursor
= (Cursor
) win
->GetCursor().GetXCursor(display
);
505 XChangeWindowAttributes (display
, xwin
, CWCursor
, &attrs
);
509 for(wxWindowList::Node
*node
= win
->GetChildren().GetFirst (); node
;
510 node
= node
->GetNext())
512 wxWindow
*child
= node
->GetData ();
513 wxXSetBusyCursor (child
, cursor
);
517 // Set the cursor to the busy cursor for all windows
518 void wxBeginBusyCursor(wxCursor
*cursor
)
521 if (wxBusyCursorCount
== 1)
523 for(wxWindowList::Node
*node
= wxTopLevelWindows
.GetFirst (); node
;
524 node
= node
->GetNext())
526 wxWindow
*win
= node
->GetData ();
527 wxXSetBusyCursor (win
, cursor
);
532 // Restore cursor to normal
533 void wxEndBusyCursor()
535 if (wxBusyCursorCount
== 0)
539 if (wxBusyCursorCount
== 0)
541 for(wxWindowList::Node
*node
= wxTopLevelWindows
.GetFirst (); node
;
542 node
= node
->GetNext())
544 wxWindow
*win
= node
->GetData ();
545 wxXSetBusyCursor (win
, NULL
);
550 // TRUE if we're between the above two calls
553 return (wxBusyCursorCount
> 0);