]> git.saurik.com Git - wxWidgets.git/blame - src/motif/cursor.cpp
Implemented wxToggleButton under Motif.
[wxWidgets.git] / src / motif / cursor.cpp
CommitLineData
4bb6408c
JS
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"
f97c9854 17#include "wx/gdicmn.h"
4bb6408c 18#include "wx/icon.h"
f97c9854
JS
19#include "wx/app.h"
20#include "wx/utils.h"
4daa4d66
CE
21#if wxUSE_IMAGE
22#include "wx/image.h"
23#endif
f97c9854 24
338dd992
JJ
25#ifdef __VMS__
26#pragma message disable nosimpint
27#endif
f97c9854
JS
28#include <Xm/Xm.h>
29#include <X11/cursorfont.h>
338dd992
JJ
30#ifdef __VMS__
31#pragma message enable nosimpint
32#endif
f97c9854
JS
33
34#include "wx/motif/private.h"
4bb6408c 35
4bb6408c 36IMPLEMENT_DYNAMIC_CLASS(wxCursor, wxBitmap)
f97c9854 37IMPLEMENT_DYNAMIC_CLASS(wxXCursor, wxObject)
4bb6408c
JS
38
39wxCursorRefData::wxCursorRefData()
40{
41 m_width = 32; m_height = 32;
f97c9854 42 m_cursorId = wxCURSOR_NONE;
4bb6408c
JS
43}
44
45wxCursorRefData::~wxCursorRefData()
46{
fd304d98 47 wxList::Node* node = m_cursors.GetFirst();
f97c9854
JS
48 while (node)
49 {
fd304d98 50 wxXCursor* c = (wxXCursor*) node->GetData();
f97c9854
JS
51 // TODO: how to delete cursor?
52 // XDestroyCursor((Display*) c->m_display, (Cursor) c->m_cursor); // ??
53 delete c;
fd304d98 54 node = node->GetNext();
f97c9854 55 }
4bb6408c
JS
56}
57
4bb6408c
JS
58wxCursor::wxCursor()
59{
60}
61
4daa4d66
CE
62#if wxUSE_IMAGE
63wxCursor::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) );
165end 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
f97c9854
JS
243wxCursor::wxCursor(const char bits[], int width, int height,
244 int hotSpotX, int hotSpotY, const char maskBits[])
4bb6408c 245{
f97c9854 246 m_refData = new wxCursorRefData;
4bb6408c 247
f97c9854
JS
248 Display *dpy = (Display*) wxGetDisplay();
249 int screen_num = DefaultScreen (dpy);
4bb6408c 250
f97c9854
JS
251 Pixmap pixmap = XCreatePixmapFromBitmapData (dpy,
252 RootWindow (dpy, DefaultScreen(dpy)),
253 (char*) bits, width, height,
254 1 , 0 , 1);
4bb6408c 255
f97c9854
JS
256 Pixmap mask_pixmap = None;
257 if (maskBits != NULL)
4bb6408c 258 {
f97c9854
JS
259 mask_pixmap = XCreatePixmapFromBitmapData (dpy,
260 RootWindow (dpy, DefaultScreen(dpy)),
261 (char*) maskBits, width, height,
262 1 , 0 , 1);
4bb6408c 263 }
f97c9854
JS
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)
4bb6408c 283 {
f97c9854 284 XFreePixmap( dpy, mask_pixmap );
4bb6408c 285 }
f97c9854
JS
286
287 if (cursor)
4bb6408c 288 {
f97c9854
JS
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;
4bb6408c 295 }
f97c9854 296 else
4bb6408c 297 {
f97c9854 298 M_CURSORDATA->m_ok = TRUE;
4bb6408c 299 }
f97c9854
JS
300}
301
302wxCursor::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 (char*) (const char*) name, &w, &h, &pixmap, &hotX, &hotY);
319
320 M_BITMAPDATA->m_width = w;
321 M_BITMAPDATA->m_height = h;
322 M_BITMAPDATA->m_depth = 1;
323
324 if ((value == BitmapFileInvalid) ||
325 (value == BitmapOpenFailed) ||
326 (value == BitmapNoMemory))
4bb6408c 327 {
4bb6408c 328 }
f97c9854 329 else
4bb6408c 330 {
f97c9854
JS
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);
338
339 // TODO: how do we determine whether hotX, hotY were read correctly?
340 if (hotX < 0 || hotY < 0)
341 {
342 hotX = hotSpotX;
343 hotY = hotSpotY;
344 }
345 if (hotX < 0 || hotY < 0)
346 {
347 hotX = 0;
348 hotY = 0;
349 }
350
351 Pixmap mask_pixmap = None;
352 Cursor cursor = XCreatePixmapCursor (dpy,
353 pixmap,
354 mask_pixmap,
355 &foreground_color,
356 &background_color,
357 hotX,
358 hotY);
359
360 XFreePixmap( dpy, pixmap );
361 if (cursor)
362 {
363 wxXCursor *c = new wxXCursor;
364
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;
369 }
4bb6408c 370 }
f97c9854
JS
371
372}
373
374// Cursors by stock number
375wxCursor::wxCursor(wxStockCursor id)
376{
377 m_refData = new wxCursorRefData;
378 M_CURSORDATA->m_cursorId = id;
47bc1060 379 M_CURSORDATA->m_ok = TRUE;
f97c9854 380
47bc1060
JS
381 WXDisplay* display = wxGetDisplay();
382 if (!display)
383 return;
384
385 WXCursor cursor = GetXCursor(display);
f97c9854 386 if (cursor)
4bb6408c 387 {
f97c9854
JS
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;
4bb6408c 393 }
f97c9854
JS
394}
395
396wxCursor::~wxCursor()
397{
398}
399
400// Motif-specific: create/get a cursor for the current display
401WXCursor wxCursor::GetXCursor(WXDisplay* display)
402{
403 if (!M_CURSORDATA)
404 return (WXCursor) 0;
fd304d98 405 wxList::Node* node = M_CURSORDATA->m_cursors.GetFirst();
f97c9854 406 while (node)
4bb6408c 407 {
fd304d98 408 wxXCursor* c = (wxXCursor*) node->GetData();
f97c9854
JS
409 if (c->m_display == display)
410 return c->m_cursor;
fd304d98 411 node = node->GetNext();
4bb6408c 412 }
f97c9854
JS
413
414 // No cursor for this display, so let's see if we're an id-type cursor.
415
416 if (M_CURSORDATA->m_cursorId != wxCURSOR_NONE)
4bb6408c 417 {
f97c9854
JS
418 WXCursor cursor = MakeCursor(display, M_CURSORDATA->m_cursorId);
419 if (cursor)
420 {
421 wxXCursor* c = new wxXCursor;
422 c->m_cursor = cursor;
423 c->m_display = display;
424 M_CURSORDATA->m_cursors.Append(c);
425 return cursor;
426 }
427 else
428 return (WXCursor) 0;
4bb6408c 429 }
4bb6408c 430
f97c9854
JS
431 // Not an id-type cursor, so we don't know how to create it.
432 return (WXCursor) 0;
4bb6408c
JS
433}
434
f97c9854
JS
435// Make a cursor from standard id
436WXCursor wxCursor::MakeCursor(WXDisplay* display, wxStockCursor id)
4bb6408c 437{
f97c9854
JS
438 Display* dpy = (Display*) display;
439 Cursor cursor = (Cursor) 0;
440
441 switch (id)
442 {
443 case wxCURSOR_WAIT:
444 {
445 cursor = XCreateFontCursor (dpy, XC_watch);
446 break;
447 }
448 case wxCURSOR_CROSS:
449 {
450 cursor = XCreateFontCursor (dpy, XC_crosshair);
451 break;
452 }
453 case wxCURSOR_CHAR:
454 {
455 // Nothing
456 break;
457 }
458 case wxCURSOR_HAND:
459 {
460 cursor = XCreateFontCursor (dpy, XC_hand1);
461 break;
462 }
463 case wxCURSOR_BULLSEYE:
464 {
465 cursor = XCreateFontCursor (dpy, XC_target);
466 break;
467 }
468 case wxCURSOR_PENCIL:
469 {
470 cursor = XCreateFontCursor (dpy, XC_pencil);
471 break;
472 }
473 case wxCURSOR_MAGNIFIER:
474 {
475 cursor = XCreateFontCursor (dpy, XC_sizing);
476 break;
477 }
478 case wxCURSOR_IBEAM:
479 {
480 cursor = XCreateFontCursor (dpy, XC_xterm);
481 break;
482 }
483 case wxCURSOR_NO_ENTRY:
484 {
485 cursor = XCreateFontCursor (dpy, XC_pirate);
486 break;
487 }
488 case wxCURSOR_LEFT_BUTTON:
489 {
490 cursor = XCreateFontCursor (dpy, XC_leftbutton);
491 break;
492 }
493 case wxCURSOR_RIGHT_BUTTON:
494 {
495 cursor = XCreateFontCursor (dpy, XC_rightbutton);
496 break;
497 }
498 case wxCURSOR_MIDDLE_BUTTON:
499 {
500 cursor = XCreateFontCursor (dpy, XC_middlebutton);
501 break;
502 }
503 case wxCURSOR_QUESTION_ARROW:
504 {
505 cursor = XCreateFontCursor (dpy, XC_question_arrow);
506 break;
507 }
508 case wxCURSOR_SIZING:
509 {
510 cursor = XCreateFontCursor (dpy, XC_sizing);
511 break;
512 }
513 case wxCURSOR_WATCH:
514 {
515 cursor = XCreateFontCursor (dpy, XC_watch);
516 break;
517 }
518 case wxCURSOR_SPRAYCAN:
519 {
520 cursor = XCreateFontCursor (dpy, XC_spraycan);
521 break;
522 }
523 case wxCURSOR_PAINT_BRUSH:
524 {
525 cursor = XCreateFontCursor (dpy, XC_spraycan);
526 break;
527 }
528 case wxCURSOR_SIZENWSE:
529 case wxCURSOR_SIZENESW:
530 {
531 // Not available in X
532 cursor = XCreateFontCursor (dpy, XC_crosshair);
533 break;
534 }
535 case wxCURSOR_SIZEWE:
536 {
537 cursor = XCreateFontCursor (dpy, XC_sb_h_double_arrow);
538 break;
539 }
540 case wxCURSOR_SIZENS:
541 {
542 cursor = XCreateFontCursor (dpy, XC_sb_v_double_arrow);
543 break;
544 }
545 case wxCURSOR_POINT_LEFT:
546 {
547 cursor = XCreateFontCursor (dpy, XC_sb_left_arrow);
548 break;
549 }
550 case wxCURSOR_POINT_RIGHT:
551 {
552 cursor = XCreateFontCursor (dpy, XC_sb_right_arrow);
553 break;
554 }
555 // (JD Huggins) added more stock cursors for X
556 // X-only cursors BEGIN
557 case wxCURSOR_CROSS_REVERSE:
558 {
559 cursor = XCreateFontCursor(dpy, XC_cross_reverse);
560 break;
561 }
562 case wxCURSOR_DOUBLE_ARROW:
563 {
564 cursor = XCreateFontCursor(dpy, XC_double_arrow);
565 break;
566 }
567 case wxCURSOR_BASED_ARROW_UP:
568 {
569 cursor = XCreateFontCursor(dpy, XC_based_arrow_up);
570 break;
571 }
572 case wxCURSOR_BASED_ARROW_DOWN:
573 {
574 cursor = XCreateFontCursor(dpy, XC_based_arrow_down);
575 break;
576 }
577 default:
578 case wxCURSOR_ARROW:
579 {
580 cursor = XCreateFontCursor (dpy, XC_top_left_arrow);
581 break;
582 }
583 case wxCURSOR_BLANK:
584 {
585 GC gc;
586 XGCValues gcv;
587 Pixmap empty_pixmap;
588 XColor blank_color;
589
590 empty_pixmap = XCreatePixmap (dpy, RootWindow (dpy, DefaultScreen (dpy)),
591 16, 16, 1);
592 gcv.function = GXxor;
593 gc = XCreateGC (dpy,
594 empty_pixmap,
595 GCFunction,
596 &gcv);
597 XCopyArea (dpy,
598 empty_pixmap,
599 empty_pixmap,
600 gc,
601 0, 0,
602 16, 16,
603 0, 0);
604 XFreeGC (dpy, gc);
605 cursor = XCreatePixmapCursor (dpy,
606 empty_pixmap,
607 empty_pixmap,
608 &blank_color,
609 &blank_color,
610 8, 8);
611
612 break;
613 }
614 }
615 return (WXCursor) cursor;
4bb6408c
JS
616}
617
618// Global cursor setting
f9e02ac7 619void wxSetCursor(const wxCursor& WXUNUSED(cursor))
4bb6408c 620{
f97c9854 621 // Nothing to do for Motif (no global cursor)
4bb6408c
JS
622}
623
624
707440dc
JS
625// ----------------------------------------------------------------------------
626// busy cursor stuff
627// ----------------------------------------------------------------------------
628
629static int wxBusyCursorCount = 0;
630
631// Helper function
632static void
633wxXSetBusyCursor (wxWindow * win, wxCursor * cursor)
634{
635 Display *display = (Display*) win->GetXDisplay();
636
637 Window xwin = (Window) win->GetXWindow();
638 if (!xwin)
639 return;
640
641 XSetWindowAttributes attrs;
642
643 if (cursor)
644 {
645 attrs.cursor = (Cursor) cursor->GetXCursor(display);
646 }
647 else
648 {
649 // Restore old cursor
650 if (win->GetCursor().Ok())
651 attrs.cursor = (Cursor) win->GetCursor().GetXCursor(display);
652 else
653 attrs.cursor = None;
654 }
655 if (xwin)
656 XChangeWindowAttributes (display, xwin, CWCursor, &attrs);
657
658 XFlush (display);
659
fd304d98
MB
660 for(wxWindowList::Node *node = win->GetChildren().GetFirst (); node;
661 node = node->GetNext())
707440dc 662 {
fd304d98 663 wxWindow *child = node->GetData ();
707440dc
JS
664 wxXSetBusyCursor (child, cursor);
665 }
666}
667
668// Set the cursor to the busy cursor for all windows
669void wxBeginBusyCursor(wxCursor *cursor)
670{
671 wxBusyCursorCount++;
672 if (wxBusyCursorCount == 1)
673 {
fd304d98
MB
674 for(wxWindowList::Node *node = wxTopLevelWindows.GetFirst (); node;
675 node = node->GetNext())
707440dc 676 {
fd304d98 677 wxWindow *win = node->GetData ();
707440dc
JS
678 wxXSetBusyCursor (win, cursor);
679 }
680 }
681}
682
683// Restore cursor to normal
684void wxEndBusyCursor()
685{
686 if (wxBusyCursorCount == 0)
687 return;
688
689 wxBusyCursorCount--;
690 if (wxBusyCursorCount == 0)
691 {
fd304d98
MB
692 for(wxWindowList::Node *node = wxTopLevelWindows.GetFirst (); node;
693 node = node->GetNext())
707440dc 694 {
fd304d98 695 wxWindow *win = node->GetData ();
707440dc
JS
696 wxXSetBusyCursor (win, NULL);
697 }
698 }
699}
700
701// TRUE if we're between the above two calls
702bool wxIsBusy()
703{
704 return (wxBusyCursorCount > 0);
705}