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"
17 #include "wx/gdicmn.h"
26 #pragma message disable nosimpint
29 #include <X11/cursorfont.h>
31 #pragma message enable nosimpint
34 #include "wx/motif/private.h"
36 IMPLEMENT_DYNAMIC_CLASS(wxCursor
, wxBitmap
)
37 IMPLEMENT_DYNAMIC_CLASS(wxXCursor
, wxObject
)
39 wxCursorRefData::wxCursorRefData()
41 m_width
= 32; m_height
= 32;
42 m_cursorId
= wxCURSOR_NONE
;
45 wxCursorRefData::~wxCursorRefData()
47 wxList::Node
* node
= m_cursors
.GetFirst();
50 wxXCursor
* c
= (wxXCursor
*) node
->GetData();
51 // TODO: how to delete cursor?
52 // XDestroyCursor((Display*) c->m_display, (Cursor) c->m_cursor); // ??
54 node
= node
->GetNext();
63 wxCursor::wxCursor(const wxImage
& image
)
65 unsigned char * rgbBits
= image
.GetData();
66 int w
= image
.GetWidth() ;
67 int h
= image
.GetHeight();
68 bool bHasMask
= image
.HasMask();
69 int imagebitcount
= (w
*h
)/8;
71 unsigned char * bits
= new unsigned char [imagebitcount
];
72 unsigned char * maskBits
= new unsigned char [imagebitcount
];
74 int i
, j
, i8
; unsigned char c
, cMask
;
75 for (i
=0; i
<imagebitcount
; i
++)
83 // possible overflow if we do the summation first ?
84 c
= rgbBits
[(i8
+j
)*3]/3 + rgbBits
[(i8
+j
)*3+1]/3 + rgbBits
[(i8
+j
)*3+2]/3;
85 //if average value is > mid grey
87 bits
[i
] = bits
[i
] | cMask
;
92 unsigned long keyMaskColor
;
96 r
= image
.GetMaskRed(),
97 g
= image
.GetMaskGreen(),
98 b
= image
.GetMaskBlue();
100 for (i
=0; i
<imagebitcount
; i
++)
108 if (rgbBits
[(i8
+j
)*3] != r
|| rgbBits
[(i8
+j
)*3+1] != g
|| rgbBits
[(i8
+j
)*3+2] != b
)
109 maskBits
[i
] = maskBits
[i
] | cMask
;
114 keyMaskColor
= (r
<< 16) | (g
<< 8) | b
;
118 for (i
=0; i
<imagebitcount
; i
++)
121 // init it to avoid compiler warnings
125 // find the most frequent color(s)
126 wxImageHistogram histogram;
127 image.ComputeHistogram(histogram);
133 long colMostFreq = 0;
134 unsigned long nMost = 0;
135 long colNextMostFreq = 0;
136 unsigned long nNext = 0;
137 for ( wxImageHistogram::iterator entry = histogram.begin();
138 entry != histogram.end();
141 value = entry->second.value;
143 if ( !bHasMask || (key != keyMaskColor) )
150 else if (value > nNext)
153 colNextMostFreq = key;
158 wxColour fg = wxColour ( (unsigned char)(colMostFreq >> 16),
159 (unsigned char)(colMostFreq >> 8),
160 (unsigned char)(colMostFreq) );
162 wxColour bg = wxColour ( (unsigned char)(colNextMostFreq >> 16),
163 (unsigned char)(colNextMostFreq >> 8),
164 (unsigned char)(colNextMostFreq) );
170 if (image
.HasOption(wxCUR_HOTSPOT_X
))
171 hotSpotX
= image
.GetOptionInt(wxCUR_HOTSPOT_X
);
175 if (image
.HasOption(wxCUR_HOTSPOT_Y
))
176 hotSpotY
= image
.GetOptionInt(wxCUR_HOTSPOT_Y
);
180 if (hotSpotX
< 0 || hotSpotX
>= w
)
182 if (hotSpotY
< 0 || hotSpotY
>= h
)
185 m_refData
= new wxCursorRefData
;
187 Display
*dpy
= (Display
*) wxGetDisplay();
188 int screen_num
= DefaultScreen (dpy
);
190 Pixmap pixmap
= XCreatePixmapFromBitmapData (dpy
,
191 RootWindow (dpy
, DefaultScreen(dpy
)),
195 Pixmap mask_pixmap
= None
;
196 if (maskBits
!= NULL
)
198 mask_pixmap
= XCreatePixmapFromBitmapData (dpy
,
199 RootWindow (dpy
, DefaultScreen(dpy
)),
200 (char*) maskBits
, w
, h
,
204 XColor foreground_color
;
205 XColor background_color
;
206 foreground_color
.pixel
= BlackPixel(dpy
, screen_num
);
207 background_color
.pixel
= WhitePixel(dpy
, screen_num
);
208 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap((WXDisplay
*) dpy
);
209 XQueryColor(dpy
, cmap
, &foreground_color
);
210 XQueryColor(dpy
, cmap
, &background_color
);
212 Cursor cursor
= XCreatePixmapCursor (dpy
,
220 XFreePixmap( dpy
, pixmap
);
221 if (mask_pixmap
!= None
)
223 XFreePixmap( dpy
, mask_pixmap
);
228 wxXCursor
*c
= new wxXCursor
;
230 c
->m_cursor
= (WXCursor
) cursor
;
231 c
->m_display
= (WXDisplay
*) dpy
;
232 M_CURSORDATA
->m_cursors
.Append(c
);
233 M_CURSORDATA
->m_ok
= TRUE
;
237 M_CURSORDATA
->m_ok
= TRUE
;
243 wxCursor::wxCursor(const char bits
[], int width
, int height
,
244 int hotSpotX
, int hotSpotY
, const char maskBits
[])
246 m_refData
= new wxCursorRefData
;
248 Display
*dpy
= (Display
*) wxGetDisplay();
249 int screen_num
= DefaultScreen (dpy
);
251 Pixmap pixmap
= XCreatePixmapFromBitmapData (dpy
,
252 RootWindow (dpy
, DefaultScreen(dpy
)),
253 (char*) bits
, width
, height
,
256 Pixmap mask_pixmap
= None
;
257 if (maskBits
!= NULL
)
259 mask_pixmap
= XCreatePixmapFromBitmapData (dpy
,
260 RootWindow (dpy
, DefaultScreen(dpy
)),
261 (char*) maskBits
, width
, height
,
265 XColor foreground_color
;
266 XColor background_color
;
267 foreground_color
.pixel
= BlackPixel(dpy
, screen_num
);
268 background_color
.pixel
= WhitePixel(dpy
, screen_num
);
269 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap((WXDisplay
*) dpy
);
270 XQueryColor(dpy
, cmap
, &foreground_color
);
271 XQueryColor(dpy
, cmap
, &background_color
);
273 Cursor cursor
= XCreatePixmapCursor (dpy
,
281 XFreePixmap( dpy
, pixmap
);
282 if (mask_pixmap
!= None
)
284 XFreePixmap( dpy
, mask_pixmap
);
289 wxXCursor
*c
= new wxXCursor
;
291 c
->m_cursor
= (WXCursor
) cursor
;
292 c
->m_display
= (WXDisplay
*) dpy
;
293 M_CURSORDATA
->m_cursors
.Append(c
);
294 M_CURSORDATA
->m_ok
= TRUE
;
298 M_CURSORDATA
->m_ok
= TRUE
;
302 wxCursor::wxCursor(const wxString
& name
, long flags
, int hotSpotX
, int hotSpotY
)
304 // Must be an XBM file
305 if (flags
!= wxBITMAP_TYPE_XBM
)
308 m_refData
= new wxCursorRefData
;
310 int hotX
= -1, hotY
= -1;
314 Display
*dpy
= (Display
*) wxGetDisplay();
315 int screen_num
= DefaultScreen (dpy
);
317 int value
= XReadBitmapFile (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)),
318 wxConstCast(name
.c_str(), char),
319 &w
, &h
, &pixmap
, &hotX
, &hotY
);
321 M_BITMAPDATA
->m_width
= w
;
322 M_BITMAPDATA
->m_height
= h
;
323 M_BITMAPDATA
->m_depth
= 1;
325 if ((value
== BitmapFileInvalid
) ||
326 (value
== BitmapOpenFailed
) ||
327 (value
== BitmapNoMemory
))
332 XColor foreground_color
;
333 XColor background_color
;
334 foreground_color
.pixel
= BlackPixel(dpy
, screen_num
);
335 background_color
.pixel
= WhitePixel(dpy
, screen_num
);
336 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap((WXDisplay
*) dpy
);
337 XQueryColor(dpy
, cmap
, &foreground_color
);
338 XQueryColor(dpy
, cmap
, &background_color
);
340 // TODO: how do we determine whether hotX, hotY were read correctly?
341 if (hotX
< 0 || hotY
< 0)
346 if (hotX
< 0 || hotY
< 0)
352 Pixmap mask_pixmap
= None
;
353 Cursor cursor
= XCreatePixmapCursor (dpy
,
361 XFreePixmap( dpy
, pixmap
);
364 wxXCursor
*c
= new wxXCursor
;
366 c
->m_cursor
= (WXCursor
) cursor
;
367 c
->m_display
= (WXDisplay
*) dpy
;
368 M_CURSORDATA
->m_cursors
.Append(c
);
369 M_CURSORDATA
->m_ok
= TRUE
;
375 // Cursors by stock number
376 wxCursor::wxCursor(wxStockCursor id
)
378 m_refData
= new wxCursorRefData
;
379 M_CURSORDATA
->m_cursorId
= id
;
380 M_CURSORDATA
->m_ok
= TRUE
;
382 WXDisplay
* display
= wxGetDisplay();
386 WXCursor cursor
= GetXCursor(display
);
389 wxXCursor
* c
= new wxXCursor
;
390 c
->m_cursor
= cursor
;
391 c
->m_display
= wxGetDisplay();
392 M_CURSORDATA
->m_cursors
.Append(c
);
393 M_CURSORDATA
->m_ok
= TRUE
;
397 wxCursor::~wxCursor()
401 // Motif-specific: create/get a cursor for the current display
402 WXCursor
wxCursor::GetXCursor(WXDisplay
* display
)
406 wxList::Node
* node
= M_CURSORDATA
->m_cursors
.GetFirst();
409 wxXCursor
* c
= (wxXCursor
*) node
->GetData();
410 if (c
->m_display
== display
)
412 node
= node
->GetNext();
415 // No cursor for this display, so let's see if we're an id-type cursor.
417 if (M_CURSORDATA
->m_cursorId
!= wxCURSOR_NONE
)
419 WXCursor cursor
= MakeCursor(display
, M_CURSORDATA
->m_cursorId
);
422 wxXCursor
* c
= new wxXCursor
;
423 c
->m_cursor
= cursor
;
424 c
->m_display
= display
;
425 M_CURSORDATA
->m_cursors
.Append(c
);
432 // Not an id-type cursor, so we don't know how to create it.
436 // Make a cursor from standard id
437 WXCursor
wxCursor::MakeCursor(WXDisplay
* display
, wxStockCursor id
)
439 Display
* dpy
= (Display
*) display
;
440 Cursor cursor
= (Cursor
) 0;
446 cursor
= XCreateFontCursor (dpy
, XC_watch
);
451 cursor
= XCreateFontCursor (dpy
, XC_crosshair
);
461 cursor
= XCreateFontCursor (dpy
, XC_hand1
);
464 case wxCURSOR_BULLSEYE
:
466 cursor
= XCreateFontCursor (dpy
, XC_target
);
469 case wxCURSOR_PENCIL
:
471 cursor
= XCreateFontCursor (dpy
, XC_pencil
);
474 case wxCURSOR_MAGNIFIER
:
476 cursor
= XCreateFontCursor (dpy
, XC_sizing
);
481 cursor
= XCreateFontCursor (dpy
, XC_xterm
);
484 case wxCURSOR_NO_ENTRY
:
486 cursor
= XCreateFontCursor (dpy
, XC_pirate
);
489 case wxCURSOR_LEFT_BUTTON
:
491 cursor
= XCreateFontCursor (dpy
, XC_leftbutton
);
494 case wxCURSOR_RIGHT_BUTTON
:
496 cursor
= XCreateFontCursor (dpy
, XC_rightbutton
);
499 case wxCURSOR_MIDDLE_BUTTON
:
501 cursor
= XCreateFontCursor (dpy
, XC_middlebutton
);
504 case wxCURSOR_QUESTION_ARROW
:
506 cursor
= XCreateFontCursor (dpy
, XC_question_arrow
);
509 case wxCURSOR_SIZING
:
511 cursor
= XCreateFontCursor (dpy
, XC_sizing
);
516 cursor
= XCreateFontCursor (dpy
, XC_watch
);
519 case wxCURSOR_SPRAYCAN
:
521 cursor
= XCreateFontCursor (dpy
, XC_spraycan
);
524 case wxCURSOR_PAINT_BRUSH
:
526 cursor
= XCreateFontCursor (dpy
, XC_spraycan
);
529 case wxCURSOR_SIZENWSE
:
530 case wxCURSOR_SIZENESW
:
532 // Not available in X
533 cursor
= XCreateFontCursor (dpy
, XC_crosshair
);
536 case wxCURSOR_SIZEWE
:
538 cursor
= XCreateFontCursor (dpy
, XC_sb_h_double_arrow
);
541 case wxCURSOR_SIZENS
:
543 cursor
= XCreateFontCursor (dpy
, XC_sb_v_double_arrow
);
546 case wxCURSOR_POINT_LEFT
:
548 cursor
= XCreateFontCursor (dpy
, XC_sb_left_arrow
);
551 case wxCURSOR_POINT_RIGHT
:
553 cursor
= XCreateFontCursor (dpy
, XC_sb_right_arrow
);
556 // (JD Huggins) added more stock cursors for X
557 // X-only cursors BEGIN
558 case wxCURSOR_CROSS_REVERSE
:
560 cursor
= XCreateFontCursor(dpy
, XC_cross_reverse
);
563 case wxCURSOR_DOUBLE_ARROW
:
565 cursor
= XCreateFontCursor(dpy
, XC_double_arrow
);
568 case wxCURSOR_BASED_ARROW_UP
:
570 cursor
= XCreateFontCursor(dpy
, XC_based_arrow_up
);
573 case wxCURSOR_BASED_ARROW_DOWN
:
575 cursor
= XCreateFontCursor(dpy
, XC_based_arrow_down
);
581 cursor
= XCreateFontCursor (dpy
, XC_top_left_arrow
);
591 empty_pixmap
= XCreatePixmap (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)),
593 gcv
.function
= GXxor
;
606 cursor
= XCreatePixmapCursor (dpy
,
616 return (WXCursor
) cursor
;
619 // Global cursor setting
620 void wxSetCursor(const wxCursor
& WXUNUSED(cursor
))
622 // Nothing to do for Motif (no global cursor)
626 // ----------------------------------------------------------------------------
628 // ----------------------------------------------------------------------------
630 static int wxBusyCursorCount
= 0;
634 wxXSetBusyCursor (wxWindow
* win
, wxCursor
* cursor
)
636 Display
*display
= (Display
*) win
->GetXDisplay();
638 Window xwin
= (Window
) win
->GetXWindow();
642 XSetWindowAttributes attrs
;
646 attrs
.cursor
= (Cursor
) cursor
->GetXCursor(display
);
650 // Restore old cursor
651 if (win
->GetCursor().Ok())
652 attrs
.cursor
= (Cursor
) win
->GetCursor().GetXCursor(display
);
657 XChangeWindowAttributes (display
, xwin
, CWCursor
, &attrs
);
661 for(wxWindowList::Node
*node
= win
->GetChildren().GetFirst (); node
;
662 node
= node
->GetNext())
664 wxWindow
*child
= node
->GetData ();
665 wxXSetBusyCursor (child
, cursor
);
669 // Set the cursor to the busy cursor for all windows
670 void wxBeginBusyCursor(wxCursor
*cursor
)
673 if (wxBusyCursorCount
== 1)
675 for(wxWindowList::Node
*node
= wxTopLevelWindows
.GetFirst (); node
;
676 node
= node
->GetNext())
678 wxWindow
*win
= node
->GetData ();
679 wxXSetBusyCursor (win
, cursor
);
684 // Restore cursor to normal
685 void wxEndBusyCursor()
687 if (wxBusyCursorCount
== 0)
691 if (wxBusyCursorCount
== 0)
693 for(wxWindowList::Node
*node
= wxTopLevelWindows
.GetFirst (); node
;
694 node
= node
->GetNext())
696 wxWindow
*win
= node
->GetData ();
697 wxXSetBusyCursor (win
, NULL
);
702 // TRUE if we're between the above two calls
705 return (wxBusyCursorCount
> 0);