Remove explicit casts to (const char *), and replace it with .c_str();
[wxWidgets.git] / src / motif / cursor.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: cursor.cpp
3 // Purpose: wxCursor class
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 17/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "cursor.h"
14 #endif
15
16 #include "wx/cursor.h"
17 #include "wx/gdicmn.h"
18 #include "wx/icon.h"
19 #include "wx/app.h"
20 #include "wx/utils.h"
21 #if wxUSE_IMAGE
22 #include "wx/image.h"
23 #endif
24
25 #ifdef __VMS__
26 #pragma message disable nosimpint
27 #endif
28 #include <Xm/Xm.h>
29 #include <X11/cursorfont.h>
30 #ifdef __VMS__
31 #pragma message enable nosimpint
32 #endif
33
34 #include "wx/motif/private.h"
35
36 IMPLEMENT_DYNAMIC_CLASS(wxCursor, wxBitmap)
37 IMPLEMENT_DYNAMIC_CLASS(wxXCursor, wxObject)
38
39 wxCursorRefData::wxCursorRefData()
40 {
41 m_width = 32; m_height = 32;
42 m_cursorId = wxCURSOR_NONE;
43 }
44
45 wxCursorRefData::~wxCursorRefData()
46 {
47 wxList::Node* node = m_cursors.GetFirst();
48 while (node)
49 {
50 wxXCursor* c = (wxXCursor*) node->GetData();
51 // TODO: how to delete cursor?
52 // XDestroyCursor((Display*) c->m_display, (Cursor) c->m_cursor); // ??
53 delete c;
54 node = node->GetNext();
55 }
56 }
57
58 wxCursor::wxCursor()
59 {
60 }
61
62 #if wxUSE_IMAGE
63 wxCursor::wxCursor(const wxImage & image)
64 {
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;
70
71 unsigned char * bits = new unsigned char [imagebitcount];
72 unsigned char * maskBits = new unsigned char [imagebitcount];
73
74 int i, j, i8; unsigned char c, cMask;
75 for (i=0; i<imagebitcount; i++)
76 {
77 bits[i] = 0;
78 i8 = i * 8;
79
80 cMask = 1;
81 for (j=0; j<8; j++)
82 {
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
86 if (c>127)
87 bits[i] = bits[i] | cMask;
88 cMask = cMask * 2;
89 }
90 }
91
92 unsigned long keyMaskColor;
93 if (bHasMask)
94 {
95 unsigned char
96 r = image.GetMaskRed(),
97 g = image.GetMaskGreen(),
98 b = image.GetMaskBlue();
99
100 for (i=0; i<imagebitcount; i++)
101 {
102 maskBits[i] = 0x0;
103 i8 = i * 8;
104
105 cMask = 1;
106 for (j=0; j<8; j++)
107 {
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;
110 cMask = cMask * 2;
111 }
112 }
113
114 keyMaskColor = (r << 16) | (g << 8) | b;
115 }
116 else // no mask
117 {
118 for (i=0; i<imagebitcount; i++)
119 maskBits[i] = 0xFF;
120
121 // init it to avoid compiler warnings
122 keyMaskColor = 0;
123 }
124 /*
125 // find the most frequent color(s)
126 wxImageHistogram histogram;
127 image.ComputeHistogram(histogram);
128
129 // colors as rrggbb
130 unsigned long key;
131 unsigned long value;
132
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();
139 ++entry )
140 {
141 value = entry->second.value;
142 key = entry->first;
143 if ( !bHasMask || (key != keyMaskColor) )
144 {
145 if (value > nMost)
146 {
147 nMost = value;
148 colMostFreq = key;
149 }
150 else if (value > nNext)
151 {
152 nNext = value;
153 colNextMostFreq = key;
154 }
155 }
156 }
157
158 wxColour fg = wxColour ( (unsigned char)(colMostFreq >> 16),
159 (unsigned char)(colMostFreq >> 8),
160 (unsigned char)(colMostFreq) );
161
162 wxColour bg = wxColour ( (unsigned char)(colNextMostFreq >> 16),
163 (unsigned char)(colNextMostFreq >> 8),
164 (unsigned char)(colNextMostFreq) );
165 end of color code
166 */
167 int hotSpotX;
168 int hotSpotY;
169
170 if (image.HasOption(wxCUR_HOTSPOT_X))
171 hotSpotX = image.GetOptionInt(wxCUR_HOTSPOT_X);
172 else
173 hotSpotX = 0;
174
175 if (image.HasOption(wxCUR_HOTSPOT_Y))
176 hotSpotY = image.GetOptionInt(wxCUR_HOTSPOT_Y);
177 else
178 hotSpotY = 0;
179
180 if (hotSpotX < 0 || hotSpotX >= w)
181 hotSpotX = 0;
182 if (hotSpotY < 0 || hotSpotY >= h)
183 hotSpotY = 0;
184
185 m_refData = new wxCursorRefData;
186
187 Display *dpy = (Display*) wxGetDisplay();
188 int screen_num = DefaultScreen (dpy);
189
190 Pixmap pixmap = XCreatePixmapFromBitmapData (dpy,
191 RootWindow (dpy, DefaultScreen(dpy)),
192 (char*) bits, w, h,
193 1 , 0 , 1);
194
195 Pixmap mask_pixmap = None;
196 if (maskBits != NULL)
197 {
198 mask_pixmap = XCreatePixmapFromBitmapData (dpy,
199 RootWindow (dpy, DefaultScreen(dpy)),
200 (char*) maskBits, w, h,
201 1 , 0 , 1);
202 }
203
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);
211
212 Cursor cursor = XCreatePixmapCursor (dpy,
213 pixmap,
214 mask_pixmap,
215 &foreground_color,
216 &background_color,
217 hotSpotX ,
218 hotSpotY);
219
220 XFreePixmap( dpy, pixmap );
221 if (mask_pixmap != None)
222 {
223 XFreePixmap( dpy, mask_pixmap );
224 }
225
226 if (cursor)
227 {
228 wxXCursor *c = new wxXCursor;
229
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;
234 }
235 else
236 {
237 M_CURSORDATA->m_ok = TRUE;
238 }
239
240 }
241 #endif
242
243 wxCursor::wxCursor(const char bits[], int width, int height,
244 int hotSpotX, int hotSpotY, const char maskBits[])
245 {
246 m_refData = new wxCursorRefData;
247
248 Display *dpy = (Display*) wxGetDisplay();
249 int screen_num = DefaultScreen (dpy);
250
251 Pixmap pixmap = XCreatePixmapFromBitmapData (dpy,
252 RootWindow (dpy, DefaultScreen(dpy)),
253 (char*) bits, width, height,
254 1 , 0 , 1);
255
256 Pixmap mask_pixmap = None;
257 if (maskBits != NULL)
258 {
259 mask_pixmap = XCreatePixmapFromBitmapData (dpy,
260 RootWindow (dpy, DefaultScreen(dpy)),
261 (char*) maskBits, width, height,
262 1 , 0 , 1);
263 }
264
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);
272
273 Cursor cursor = XCreatePixmapCursor (dpy,
274 pixmap,
275 mask_pixmap,
276 &foreground_color,
277 &background_color,
278 hotSpotX ,
279 hotSpotY);
280
281 XFreePixmap( dpy, pixmap );
282 if (mask_pixmap != None)
283 {
284 XFreePixmap( dpy, mask_pixmap );
285 }
286
287 if (cursor)
288 {
289 wxXCursor *c = new wxXCursor;
290
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;
295 }
296 else
297 {
298 M_CURSORDATA->m_ok = TRUE;
299 }
300 }
301
302 wxCursor::wxCursor(const wxString& name, long flags, int hotSpotX, int hotSpotY)
303 {
304 // Must be an XBM file
305 if (flags != wxBITMAP_TYPE_XBM)
306 return;
307
308 m_refData = new wxCursorRefData;
309
310 int hotX = -1, hotY = -1;
311 unsigned int w, h;
312 Pixmap pixmap;
313
314 Display *dpy = (Display*) wxGetDisplay();
315 int screen_num = DefaultScreen (dpy);
316
317 int value = XReadBitmapFile (dpy, RootWindow (dpy, DefaultScreen (dpy)),
318 wxConstCast(name.c_str(), char),
319 &w, &h, &pixmap, &hotX, &hotY);
320
321 M_BITMAPDATA->m_width = w;
322 M_BITMAPDATA->m_height = h;
323 M_BITMAPDATA->m_depth = 1;
324
325 if ((value == BitmapFileInvalid) ||
326 (value == BitmapOpenFailed) ||
327 (value == BitmapNoMemory))
328 {
329 }
330 else
331 {
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);
339
340 // TODO: how do we determine whether hotX, hotY were read correctly?
341 if (hotX < 0 || hotY < 0)
342 {
343 hotX = hotSpotX;
344 hotY = hotSpotY;
345 }
346 if (hotX < 0 || hotY < 0)
347 {
348 hotX = 0;
349 hotY = 0;
350 }
351
352 Pixmap mask_pixmap = None;
353 Cursor cursor = XCreatePixmapCursor (dpy,
354 pixmap,
355 mask_pixmap,
356 &foreground_color,
357 &background_color,
358 hotX,
359 hotY);
360
361 XFreePixmap( dpy, pixmap );
362 if (cursor)
363 {
364 wxXCursor *c = new wxXCursor;
365
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;
370 }
371 }
372
373 }
374
375 // Cursors by stock number
376 wxCursor::wxCursor(wxStockCursor id)
377 {
378 m_refData = new wxCursorRefData;
379 M_CURSORDATA->m_cursorId = id;
380 M_CURSORDATA->m_ok = TRUE;
381
382 WXDisplay* display = wxGetDisplay();
383 if (!display)
384 return;
385
386 WXCursor cursor = GetXCursor(display);
387 if (cursor)
388 {
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;
394 }
395 }
396
397 wxCursor::~wxCursor()
398 {
399 }
400
401 // Motif-specific: create/get a cursor for the current display
402 WXCursor wxCursor::GetXCursor(WXDisplay* display)
403 {
404 if (!M_CURSORDATA)
405 return (WXCursor) 0;
406 wxList::Node* node = M_CURSORDATA->m_cursors.GetFirst();
407 while (node)
408 {
409 wxXCursor* c = (wxXCursor*) node->GetData();
410 if (c->m_display == display)
411 return c->m_cursor;
412 node = node->GetNext();
413 }
414
415 // No cursor for this display, so let's see if we're an id-type cursor.
416
417 if (M_CURSORDATA->m_cursorId != wxCURSOR_NONE)
418 {
419 WXCursor cursor = MakeCursor(display, M_CURSORDATA->m_cursorId);
420 if (cursor)
421 {
422 wxXCursor* c = new wxXCursor;
423 c->m_cursor = cursor;
424 c->m_display = display;
425 M_CURSORDATA->m_cursors.Append(c);
426 return cursor;
427 }
428 else
429 return (WXCursor) 0;
430 }
431
432 // Not an id-type cursor, so we don't know how to create it.
433 return (WXCursor) 0;
434 }
435
436 // Make a cursor from standard id
437 WXCursor wxCursor::MakeCursor(WXDisplay* display, wxStockCursor id)
438 {
439 Display* dpy = (Display*) display;
440 Cursor cursor = (Cursor) 0;
441
442 switch (id)
443 {
444 case wxCURSOR_WAIT:
445 {
446 cursor = XCreateFontCursor (dpy, XC_watch);
447 break;
448 }
449 case wxCURSOR_CROSS:
450 {
451 cursor = XCreateFontCursor (dpy, XC_crosshair);
452 break;
453 }
454 case wxCURSOR_CHAR:
455 {
456 // Nothing
457 break;
458 }
459 case wxCURSOR_HAND:
460 {
461 cursor = XCreateFontCursor (dpy, XC_hand1);
462 break;
463 }
464 case wxCURSOR_BULLSEYE:
465 {
466 cursor = XCreateFontCursor (dpy, XC_target);
467 break;
468 }
469 case wxCURSOR_PENCIL:
470 {
471 cursor = XCreateFontCursor (dpy, XC_pencil);
472 break;
473 }
474 case wxCURSOR_MAGNIFIER:
475 {
476 cursor = XCreateFontCursor (dpy, XC_sizing);
477 break;
478 }
479 case wxCURSOR_IBEAM:
480 {
481 cursor = XCreateFontCursor (dpy, XC_xterm);
482 break;
483 }
484 case wxCURSOR_NO_ENTRY:
485 {
486 cursor = XCreateFontCursor (dpy, XC_pirate);
487 break;
488 }
489 case wxCURSOR_LEFT_BUTTON:
490 {
491 cursor = XCreateFontCursor (dpy, XC_leftbutton);
492 break;
493 }
494 case wxCURSOR_RIGHT_BUTTON:
495 {
496 cursor = XCreateFontCursor (dpy, XC_rightbutton);
497 break;
498 }
499 case wxCURSOR_MIDDLE_BUTTON:
500 {
501 cursor = XCreateFontCursor (dpy, XC_middlebutton);
502 break;
503 }
504 case wxCURSOR_QUESTION_ARROW:
505 {
506 cursor = XCreateFontCursor (dpy, XC_question_arrow);
507 break;
508 }
509 case wxCURSOR_SIZING:
510 {
511 cursor = XCreateFontCursor (dpy, XC_sizing);
512 break;
513 }
514 case wxCURSOR_WATCH:
515 {
516 cursor = XCreateFontCursor (dpy, XC_watch);
517 break;
518 }
519 case wxCURSOR_SPRAYCAN:
520 {
521 cursor = XCreateFontCursor (dpy, XC_spraycan);
522 break;
523 }
524 case wxCURSOR_PAINT_BRUSH:
525 {
526 cursor = XCreateFontCursor (dpy, XC_spraycan);
527 break;
528 }
529 case wxCURSOR_SIZENWSE:
530 case wxCURSOR_SIZENESW:
531 {
532 // Not available in X
533 cursor = XCreateFontCursor (dpy, XC_crosshair);
534 break;
535 }
536 case wxCURSOR_SIZEWE:
537 {
538 cursor = XCreateFontCursor (dpy, XC_sb_h_double_arrow);
539 break;
540 }
541 case wxCURSOR_SIZENS:
542 {
543 cursor = XCreateFontCursor (dpy, XC_sb_v_double_arrow);
544 break;
545 }
546 case wxCURSOR_POINT_LEFT:
547 {
548 cursor = XCreateFontCursor (dpy, XC_sb_left_arrow);
549 break;
550 }
551 case wxCURSOR_POINT_RIGHT:
552 {
553 cursor = XCreateFontCursor (dpy, XC_sb_right_arrow);
554 break;
555 }
556 // (JD Huggins) added more stock cursors for X
557 // X-only cursors BEGIN
558 case wxCURSOR_CROSS_REVERSE:
559 {
560 cursor = XCreateFontCursor(dpy, XC_cross_reverse);
561 break;
562 }
563 case wxCURSOR_DOUBLE_ARROW:
564 {
565 cursor = XCreateFontCursor(dpy, XC_double_arrow);
566 break;
567 }
568 case wxCURSOR_BASED_ARROW_UP:
569 {
570 cursor = XCreateFontCursor(dpy, XC_based_arrow_up);
571 break;
572 }
573 case wxCURSOR_BASED_ARROW_DOWN:
574 {
575 cursor = XCreateFontCursor(dpy, XC_based_arrow_down);
576 break;
577 }
578 default:
579 case wxCURSOR_ARROW:
580 {
581 cursor = XCreateFontCursor (dpy, XC_top_left_arrow);
582 break;
583 }
584 case wxCURSOR_BLANK:
585 {
586 GC gc;
587 XGCValues gcv;
588 Pixmap empty_pixmap;
589 XColor blank_color;
590
591 empty_pixmap = XCreatePixmap (dpy, RootWindow (dpy, DefaultScreen (dpy)),
592 16, 16, 1);
593 gcv.function = GXxor;
594 gc = XCreateGC (dpy,
595 empty_pixmap,
596 GCFunction,
597 &gcv);
598 XCopyArea (dpy,
599 empty_pixmap,
600 empty_pixmap,
601 gc,
602 0, 0,
603 16, 16,
604 0, 0);
605 XFreeGC (dpy, gc);
606 cursor = XCreatePixmapCursor (dpy,
607 empty_pixmap,
608 empty_pixmap,
609 &blank_color,
610 &blank_color,
611 8, 8);
612
613 break;
614 }
615 }
616 return (WXCursor) cursor;
617 }
618
619 // Global cursor setting
620 void wxSetCursor(const wxCursor& WXUNUSED(cursor))
621 {
622 // Nothing to do for Motif (no global cursor)
623 }
624
625
626 // ----------------------------------------------------------------------------
627 // busy cursor stuff
628 // ----------------------------------------------------------------------------
629
630 static int wxBusyCursorCount = 0;
631
632 // Helper function
633 static void
634 wxXSetBusyCursor (wxWindow * win, wxCursor * cursor)
635 {
636 Display *display = (Display*) win->GetXDisplay();
637
638 Window xwin = (Window) win->GetXWindow();
639 if (!xwin)
640 return;
641
642 XSetWindowAttributes attrs;
643
644 if (cursor)
645 {
646 attrs.cursor = (Cursor) cursor->GetXCursor(display);
647 }
648 else
649 {
650 // Restore old cursor
651 if (win->GetCursor().Ok())
652 attrs.cursor = (Cursor) win->GetCursor().GetXCursor(display);
653 else
654 attrs.cursor = None;
655 }
656 if (xwin)
657 XChangeWindowAttributes (display, xwin, CWCursor, &attrs);
658
659 XFlush (display);
660
661 for(wxWindowList::Node *node = win->GetChildren().GetFirst (); node;
662 node = node->GetNext())
663 {
664 wxWindow *child = node->GetData ();
665 wxXSetBusyCursor (child, cursor);
666 }
667 }
668
669 // Set the cursor to the busy cursor for all windows
670 void wxBeginBusyCursor(wxCursor *cursor)
671 {
672 wxBusyCursorCount++;
673 if (wxBusyCursorCount == 1)
674 {
675 for(wxWindowList::Node *node = wxTopLevelWindows.GetFirst (); node;
676 node = node->GetNext())
677 {
678 wxWindow *win = node->GetData ();
679 wxXSetBusyCursor (win, cursor);
680 }
681 }
682 }
683
684 // Restore cursor to normal
685 void wxEndBusyCursor()
686 {
687 if (wxBusyCursorCount == 0)
688 return;
689
690 wxBusyCursorCount--;
691 if (wxBusyCursorCount == 0)
692 {
693 for(wxWindowList::Node *node = wxTopLevelWindows.GetFirst (); node;
694 node = node->GetNext())
695 {
696 wxWindow *win = node->GetData ();
697 wxXSetBusyCursor (win, NULL);
698 }
699 }
700 }
701
702 // TRUE if we're between the above two calls
703 bool wxIsBusy()
704 {
705 return (wxBusyCursorCount > 0);
706 }