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 wxNode
* node
= m_cursors
.First();
50 wxXCursor
* c
= (wxXCursor
*) node
->Data();
51 // TODO: how to delete cursor?
52 // XDestroyCursor((Display*) c->m_display, (Cursor) c->m_cursor); // ??
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 (char*) (const char*) name
, &w
, &h
, &pixmap
, &hotX
, &hotY
);
320 M_BITMAPDATA
->m_width
= w
;
321 M_BITMAPDATA
->m_height
= h
;
322 M_BITMAPDATA
->m_depth
= 1;
324 if ((value
== BitmapFileInvalid
) ||
325 (value
== BitmapOpenFailed
) ||
326 (value
== BitmapNoMemory
))
331 XColor foreground_color
;
332 XColor background_color
;
333 foreground_color
.pixel
= BlackPixel(dpy
, screen_num
);
334 background_color
.pixel
= WhitePixel(dpy
, screen_num
);
335 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap((WXDisplay
*) dpy
);
336 XQueryColor(dpy
, cmap
, &foreground_color
);
337 XQueryColor(dpy
, cmap
, &background_color
);
339 // TODO: how do we determine whether hotX, hotY were read correctly?
340 if (hotX
< 0 || hotY
< 0)
345 if (hotX
< 0 || hotY
< 0)
351 Pixmap mask_pixmap
= None
;
352 Cursor cursor
= XCreatePixmapCursor (dpy
,
360 XFreePixmap( dpy
, pixmap
);
363 wxXCursor
*c
= new wxXCursor
;
365 c
->m_cursor
= (WXCursor
) cursor
;
366 c
->m_display
= (WXDisplay
*) dpy
;
367 M_CURSORDATA
->m_cursors
.Append(c
);
368 M_CURSORDATA
->m_ok
= TRUE
;
374 // Cursors by stock number
375 wxCursor::wxCursor(wxStockCursor id
)
377 m_refData
= new wxCursorRefData
;
378 M_CURSORDATA
->m_cursorId
= id
;
379 M_CURSORDATA
->m_ok
= TRUE
;
381 WXDisplay
* display
= wxGetDisplay();
385 WXCursor cursor
= GetXCursor(display
);
388 wxXCursor
* c
= new wxXCursor
;
389 c
->m_cursor
= cursor
;
390 c
->m_display
= wxGetDisplay();
391 M_CURSORDATA
->m_cursors
.Append(c
);
392 M_CURSORDATA
->m_ok
= TRUE
;
396 wxCursor::~wxCursor()
400 // Motif-specific: create/get a cursor for the current display
401 WXCursor
wxCursor::GetXCursor(WXDisplay
* display
)
405 wxNode
* node
= M_CURSORDATA
->m_cursors
.First();
408 wxXCursor
* c
= (wxXCursor
*) node
->Data();
409 if (c
->m_display
== display
)
414 // No cursor for this display, so let's see if we're an id-type cursor.
416 if (M_CURSORDATA
->m_cursorId
!= wxCURSOR_NONE
)
418 WXCursor cursor
= MakeCursor(display
, M_CURSORDATA
->m_cursorId
);
421 wxXCursor
* c
= new wxXCursor
;
422 c
->m_cursor
= cursor
;
423 c
->m_display
= display
;
424 M_CURSORDATA
->m_cursors
.Append(c
);
431 // Not an id-type cursor, so we don't know how to create it.
435 // Make a cursor from standard id
436 WXCursor
wxCursor::MakeCursor(WXDisplay
* display
, wxStockCursor id
)
438 Display
* dpy
= (Display
*) display
;
439 Cursor cursor
= (Cursor
) 0;
445 cursor
= XCreateFontCursor (dpy
, XC_watch
);
450 cursor
= XCreateFontCursor (dpy
, XC_crosshair
);
460 cursor
= XCreateFontCursor (dpy
, XC_hand1
);
463 case wxCURSOR_BULLSEYE
:
465 cursor
= XCreateFontCursor (dpy
, XC_target
);
468 case wxCURSOR_PENCIL
:
470 cursor
= XCreateFontCursor (dpy
, XC_pencil
);
473 case wxCURSOR_MAGNIFIER
:
475 cursor
= XCreateFontCursor (dpy
, XC_sizing
);
480 cursor
= XCreateFontCursor (dpy
, XC_xterm
);
483 case wxCURSOR_NO_ENTRY
:
485 cursor
= XCreateFontCursor (dpy
, XC_pirate
);
488 case wxCURSOR_LEFT_BUTTON
:
490 cursor
= XCreateFontCursor (dpy
, XC_leftbutton
);
493 case wxCURSOR_RIGHT_BUTTON
:
495 cursor
= XCreateFontCursor (dpy
, XC_rightbutton
);
498 case wxCURSOR_MIDDLE_BUTTON
:
500 cursor
= XCreateFontCursor (dpy
, XC_middlebutton
);
503 case wxCURSOR_QUESTION_ARROW
:
505 cursor
= XCreateFontCursor (dpy
, XC_question_arrow
);
508 case wxCURSOR_SIZING
:
510 cursor
= XCreateFontCursor (dpy
, XC_sizing
);
515 cursor
= XCreateFontCursor (dpy
, XC_watch
);
518 case wxCURSOR_SPRAYCAN
:
520 cursor
= XCreateFontCursor (dpy
, XC_spraycan
);
523 case wxCURSOR_PAINT_BRUSH
:
525 cursor
= XCreateFontCursor (dpy
, XC_spraycan
);
528 case wxCURSOR_SIZENWSE
:
529 case wxCURSOR_SIZENESW
:
531 // Not available in X
532 cursor
= XCreateFontCursor (dpy
, XC_crosshair
);
535 case wxCURSOR_SIZEWE
:
537 cursor
= XCreateFontCursor (dpy
, XC_sb_h_double_arrow
);
540 case wxCURSOR_SIZENS
:
542 cursor
= XCreateFontCursor (dpy
, XC_sb_v_double_arrow
);
545 case wxCURSOR_POINT_LEFT
:
547 cursor
= XCreateFontCursor (dpy
, XC_sb_left_arrow
);
550 case wxCURSOR_POINT_RIGHT
:
552 cursor
= XCreateFontCursor (dpy
, XC_sb_right_arrow
);
555 // (JD Huggins) added more stock cursors for X
556 // X-only cursors BEGIN
557 case wxCURSOR_CROSS_REVERSE
:
559 cursor
= XCreateFontCursor(dpy
, XC_cross_reverse
);
562 case wxCURSOR_DOUBLE_ARROW
:
564 cursor
= XCreateFontCursor(dpy
, XC_double_arrow
);
567 case wxCURSOR_BASED_ARROW_UP
:
569 cursor
= XCreateFontCursor(dpy
, XC_based_arrow_up
);
572 case wxCURSOR_BASED_ARROW_DOWN
:
574 cursor
= XCreateFontCursor(dpy
, XC_based_arrow_down
);
580 cursor
= XCreateFontCursor (dpy
, XC_top_left_arrow
);
590 empty_pixmap
= XCreatePixmap (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)),
592 gcv
.function
= GXxor
;
605 cursor
= XCreatePixmapCursor (dpy
,
615 return (WXCursor
) cursor
;
618 // Global cursor setting
619 void wxSetCursor(const wxCursor
& WXUNUSED(cursor
))
621 // Nothing to do for Motif (no global cursor)
625 // ----------------------------------------------------------------------------
627 // ----------------------------------------------------------------------------
629 static int wxBusyCursorCount
= 0;
633 wxXSetBusyCursor (wxWindow
* win
, wxCursor
* cursor
)
635 Display
*display
= (Display
*) win
->GetXDisplay();
637 Window xwin
= (Window
) win
->GetXWindow();
641 XSetWindowAttributes attrs
;
645 attrs
.cursor
= (Cursor
) cursor
->GetXCursor(display
);
649 // Restore old cursor
650 if (win
->GetCursor().Ok())
651 attrs
.cursor
= (Cursor
) win
->GetCursor().GetXCursor(display
);
656 XChangeWindowAttributes (display
, xwin
, CWCursor
, &attrs
);
660 for(wxNode
*node
= win
->GetChildren().First (); node
; node
= node
->Next())
662 wxWindow
*child
= (wxWindow
*) node
->Data ();
663 wxXSetBusyCursor (child
, cursor
);
667 // Set the cursor to the busy cursor for all windows
668 void wxBeginBusyCursor(wxCursor
*cursor
)
671 if (wxBusyCursorCount
== 1)
673 for(wxNode
*node
= wxTopLevelWindows
.First (); node
; node
= node
->Next())
675 wxWindow
*win
= (wxWindow
*) node
->Data ();
676 wxXSetBusyCursor (win
, cursor
);
681 // Restore cursor to normal
682 void wxEndBusyCursor()
684 if (wxBusyCursorCount
== 0)
688 if (wxBusyCursorCount
== 0)
690 for(wxNode
*node
= wxTopLevelWindows
.First (); node
; node
= node
->Next())
692 wxWindow
*win
= (wxWindow
*) node
->Data ();
693 wxXSetBusyCursor (win
, NULL
);
698 // TRUE if we're between the above two calls
701 return (wxBusyCursorCount
> 0);