Removed unnecessay code.
[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/app.h"
18 #include "wx/utils.h"
19 #include "wx/list.h"
20 #if wxUSE_IMAGE
21 #include "wx/image.h"
22 #endif
23
24 #ifdef __VMS__
25 #pragma message disable nosimpint
26 #endif
27 #include <Xm/Xm.h>
28 #include <X11/cursorfont.h>
29 #ifdef __VMS__
30 #pragma message enable nosimpint
31 #endif
32
33 #include "wx/motif/private.h"
34
35 // Cursor for one display, so we can choose the correct one for
36 // the current display.
37 class wxXCursor
38 {
39 public:
40 WXDisplay* m_display;
41 WXCursor m_cursor;
42 };
43
44 WX_DECLARE_LIST(wxXCursor, wxXCursorList);
45 #include "wx/listimpl.cpp"
46 WX_DEFINE_LIST(wxXCursorList);
47
48 class WXDLLEXPORT wxCursorRefData: public wxObjectRefData
49 {
50 friend class WXDLLEXPORT wxCursor;
51 public:
52 wxCursorRefData();
53 ~wxCursorRefData();
54
55 wxXCursorList m_cursors; // wxXCursor objects, one per display
56 wxStockCursor m_cursorId; // wxWindows standard cursor id
57 };
58
59 #define M_CURSORDATA ((wxCursorRefData *)m_refData)
60 #define M_CURSORHANDLERDATA ((wxCursorRefData *)bitmap->m_refData)
61
62 IMPLEMENT_DYNAMIC_CLASS(wxCursor, wxObject)
63
64 wxCursorRefData::wxCursorRefData()
65 {
66 m_cursorId = wxCURSOR_NONE;
67 }
68
69 wxCursorRefData::~wxCursorRefData()
70 {
71 wxXCursorList::Node* node = m_cursors.GetFirst();
72 while (node)
73 {
74 wxXCursor* c = node->GetData();
75 XFreeCursor((Display*) c->m_display, (Cursor) c->m_cursor);
76 delete c;
77 node = node->GetNext();
78 }
79 }
80
81 wxCursor::wxCursor()
82 {
83 }
84
85 #if wxUSE_IMAGE
86 wxCursor::wxCursor(const wxImage & image)
87 {
88 unsigned char * rgbBits = image.GetData();
89 int w = image.GetWidth() ;
90 int h = image.GetHeight();
91 bool bHasMask = image.HasMask();
92 int imagebitcount = (w*h)/8;
93
94 unsigned char * bits = new unsigned char [imagebitcount];
95 unsigned char * maskBits = new unsigned char [imagebitcount];
96
97 int i, j, i8; unsigned char c, cMask;
98 for (i=0; i<imagebitcount; i++)
99 {
100 bits[i] = 0;
101 i8 = i * 8;
102
103 cMask = 1;
104 for (j=0; j<8; j++)
105 {
106 // possible overflow if we do the summation first ?
107 c = rgbBits[(i8+j)*3]/3 + rgbBits[(i8+j)*3+1]/3 + rgbBits[(i8+j)*3+2]/3;
108 //if average value is > mid grey
109 if (c>127)
110 bits[i] = bits[i] | cMask;
111 cMask = cMask * 2;
112 }
113 }
114
115 if (bHasMask)
116 {
117 unsigned char
118 r = image.GetMaskRed(),
119 g = image.GetMaskGreen(),
120 b = image.GetMaskBlue();
121
122 for (i=0; i<imagebitcount; i++)
123 {
124 maskBits[i] = 0x0;
125 i8 = i * 8;
126
127 cMask = 1;
128 for (j=0; j<8; j++)
129 {
130 if (rgbBits[(i8+j)*3] != r || rgbBits[(i8+j)*3+1] != g || rgbBits[(i8+j)*3+2] != b)
131 maskBits[i] = maskBits[i] | cMask;
132 cMask = cMask * 2;
133 }
134 }
135 }
136 else // no mask
137 {
138 for (i=0; i<imagebitcount; i++)
139 maskBits[i] = 0xFF;
140 }
141
142 int hotSpotX;
143 int hotSpotY;
144
145 if (image.HasOption(wxCUR_HOTSPOT_X))
146 hotSpotX = image.GetOptionInt(wxCUR_HOTSPOT_X);
147 else
148 hotSpotX = 0;
149
150 if (image.HasOption(wxCUR_HOTSPOT_Y))
151 hotSpotY = image.GetOptionInt(wxCUR_HOTSPOT_Y);
152 else
153 hotSpotY = 0;
154
155 if (hotSpotX < 0 || hotSpotX >= w)
156 hotSpotX = 0;
157 if (hotSpotY < 0 || hotSpotY >= h)
158 hotSpotY = 0;
159
160 m_refData = new wxCursorRefData;
161
162 Display *dpy = (Display*) wxGetDisplay();
163 int screen_num = DefaultScreen (dpy);
164
165 Pixmap pixmap = XCreatePixmapFromBitmapData (dpy,
166 RootWindow (dpy, DefaultScreen(dpy)),
167 (char*) bits, w, h,
168 1 , 0 , 1);
169
170 Pixmap mask_pixmap = None;
171 if (maskBits != NULL)
172 {
173 mask_pixmap = XCreatePixmapFromBitmapData (dpy,
174 RootWindow (dpy, DefaultScreen(dpy)),
175 (char*) maskBits, w, h,
176 1 , 0 , 1);
177 }
178
179 XColor foreground_color;
180 XColor background_color;
181 foreground_color.pixel = BlackPixel(dpy, screen_num);
182 background_color.pixel = WhitePixel(dpy, screen_num);
183 Colormap cmap = (Colormap) wxTheApp->GetMainColormap((WXDisplay*) dpy);
184 XQueryColor(dpy, cmap, &foreground_color);
185 XQueryColor(dpy, cmap, &background_color);
186
187 Cursor cursor = XCreatePixmapCursor (dpy,
188 pixmap,
189 mask_pixmap,
190 &foreground_color,
191 &background_color,
192 hotSpotX ,
193 hotSpotY);
194
195 XFreePixmap( dpy, pixmap );
196 if (mask_pixmap != None)
197 {
198 XFreePixmap( dpy, mask_pixmap );
199 }
200
201 if (cursor)
202 {
203 wxXCursor *c = new wxXCursor;
204
205 c->m_cursor = (WXCursor) cursor;
206 c->m_display = (WXDisplay*) dpy;
207 M_CURSORDATA->m_cursors.Append(c);
208 }
209 }
210 #endif
211
212 wxCursor::wxCursor(const char bits[], int width, int height,
213 int hotSpotX, int hotSpotY, const char maskBits[])
214 {
215 m_refData = new wxCursorRefData;
216
217 Display *dpy = (Display*) wxGetDisplay();
218 int screen_num = DefaultScreen (dpy);
219
220 Pixmap pixmap = XCreatePixmapFromBitmapData (dpy,
221 RootWindow (dpy, DefaultScreen(dpy)),
222 (char*) bits, width, height,
223 1 , 0 , 1);
224
225 Pixmap mask_pixmap = None;
226 if (maskBits != NULL)
227 {
228 mask_pixmap = XCreatePixmapFromBitmapData (dpy,
229 RootWindow (dpy, DefaultScreen(dpy)),
230 (char*) maskBits, width, height,
231 1 , 0 , 1);
232 }
233
234 XColor foreground_color;
235 XColor background_color;
236 foreground_color.pixel = BlackPixel(dpy, screen_num);
237 background_color.pixel = WhitePixel(dpy, screen_num);
238 Colormap cmap = (Colormap) wxTheApp->GetMainColormap((WXDisplay*) dpy);
239 XQueryColor(dpy, cmap, &foreground_color);
240 XQueryColor(dpy, cmap, &background_color);
241
242 Cursor cursor = XCreatePixmapCursor (dpy,
243 pixmap,
244 mask_pixmap,
245 &foreground_color,
246 &background_color,
247 hotSpotX ,
248 hotSpotY);
249
250 XFreePixmap( dpy, pixmap );
251 if (mask_pixmap != None)
252 {
253 XFreePixmap( dpy, mask_pixmap );
254 }
255
256 if (cursor)
257 {
258 wxXCursor *c = new wxXCursor;
259
260 c->m_cursor = (WXCursor) cursor;
261 c->m_display = (WXDisplay*) dpy;
262 M_CURSORDATA->m_cursors.Append(c);
263 }
264 }
265
266 wxCursor::wxCursor(const wxString& name, long flags, int hotSpotX, int hotSpotY)
267 {
268 // Must be an XBM file
269 if (flags != wxBITMAP_TYPE_XBM)
270 return;
271
272 m_refData = new wxCursorRefData;
273
274 int hotX = -1, hotY = -1;
275 unsigned int w, h;
276 Pixmap pixmap;
277
278 Display *dpy = (Display*) wxGetDisplay();
279 int screen_num = DefaultScreen (dpy);
280
281 int value = XReadBitmapFile (dpy, RootWindow (dpy, DefaultScreen (dpy)),
282 wxConstCast(name.c_str(), char),
283 &w, &h, &pixmap, &hotX, &hotY);
284
285 if ((value == BitmapFileInvalid) ||
286 (value == BitmapOpenFailed) ||
287 (value == BitmapNoMemory))
288 {
289 }
290 else
291 {
292 XColor foreground_color;
293 XColor background_color;
294 foreground_color.pixel = BlackPixel(dpy, screen_num);
295 background_color.pixel = WhitePixel(dpy, screen_num);
296 Colormap cmap = (Colormap) wxTheApp->GetMainColormap((WXDisplay*) dpy);
297 XQueryColor(dpy, cmap, &foreground_color);
298 XQueryColor(dpy, cmap, &background_color);
299
300 // TODO: how do we determine whether hotX, hotY were read correctly?
301 if (hotX < 0 || hotY < 0)
302 {
303 hotX = hotSpotX;
304 hotY = hotSpotY;
305 }
306 if (hotX < 0 || hotY < 0)
307 {
308 hotX = 0;
309 hotY = 0;
310 }
311
312 Pixmap mask_pixmap = None;
313 Cursor cursor = XCreatePixmapCursor (dpy,
314 pixmap,
315 mask_pixmap,
316 &foreground_color,
317 &background_color,
318 hotX,
319 hotY);
320
321 XFreePixmap( dpy, pixmap );
322 if (cursor)
323 {
324 wxXCursor *c = new wxXCursor;
325
326 c->m_cursor = (WXCursor) cursor;
327 c->m_display = (WXDisplay*) dpy;
328 M_CURSORDATA->m_cursors.Append(c);
329 }
330 }
331
332 }
333
334 // Cursors by stock number
335 wxCursor::wxCursor(wxStockCursor id)
336 {
337 m_refData = new wxCursorRefData;
338 M_CURSORDATA->m_cursorId = id;
339 }
340
341 wxCursor::~wxCursor()
342 {
343 }
344
345 bool wxCursor::Ok() const
346 {
347 return m_refData != NULL;
348 }
349
350 // Motif-specific: create/get a cursor for the current display
351 WXCursor wxCursor::GetXCursor(WXDisplay* display)
352 {
353 if (!M_CURSORDATA)
354 return (WXCursor) 0;
355 wxXCursorList::Node* node = M_CURSORDATA->m_cursors.GetFirst();
356 while (node)
357 {
358 wxXCursor* c = node->GetData();
359 if (c->m_display == display)
360 return c->m_cursor;
361 node = node->GetNext();
362 }
363
364 // No cursor for this display, so let's see if we're an id-type cursor.
365
366 if (M_CURSORDATA->m_cursorId != wxCURSOR_NONE)
367 {
368 WXCursor cursor = MakeCursor(display, M_CURSORDATA->m_cursorId);
369 if (cursor)
370 {
371 wxXCursor* c = new wxXCursor;
372 c->m_cursor = cursor;
373 c->m_display = display;
374 M_CURSORDATA->m_cursors.Append(c);
375 return cursor;
376 }
377 else
378 return (WXCursor) 0;
379 }
380
381 // Not an id-type cursor, so we don't know how to create it.
382 return (WXCursor) 0;
383 }
384
385 // Make a cursor from standard id
386 WXCursor wxCursor::MakeCursor(WXDisplay* display, wxStockCursor id)
387 {
388 Display* dpy = (Display*) display;
389 Cursor cursor = (Cursor) 0;
390 int x_cur = -1;
391
392 switch (id)
393 {
394 case wxCURSOR_WAIT: x_cur = XC_watch; break;
395 case wxCURSOR_CROSS: x_cur = XC_crosshair; break;
396 case wxCURSOR_CHAR: return (WXCursor)cursor; break;
397 case wxCURSOR_HAND: x_cur = XC_hand1; break;
398 case wxCURSOR_BULLSEYE: x_cur = XC_target; break;
399 case wxCURSOR_PENCIL: x_cur = XC_pencil; break;
400 case wxCURSOR_MAGNIFIER: x_cur = XC_sizing; break;
401 case wxCURSOR_IBEAM: x_cur = XC_xterm; break;
402 case wxCURSOR_NO_ENTRY: x_cur = XC_pirate; break;
403 case wxCURSOR_LEFT_BUTTON: x_cur = XC_leftbutton; break;
404 case wxCURSOR_RIGHT_BUTTON: x_cur = XC_rightbutton; break;
405 case wxCURSOR_MIDDLE_BUTTON: x_cur = XC_middlebutton; break;
406 case wxCURSOR_QUESTION_ARROW: x_cur = XC_question_arrow; break;
407 case wxCURSOR_SIZING: x_cur = XC_sizing; break;
408 case wxCURSOR_WATCH: x_cur = XC_watch; break;
409 case wxCURSOR_SPRAYCAN: x_cur = XC_spraycan; break;
410 case wxCURSOR_PAINT_BRUSH: x_cur = XC_spraycan; break;
411 case wxCURSOR_SIZENWSE:
412 case wxCURSOR_SIZENESW: x_cur = XC_crosshair; break;
413 case wxCURSOR_SIZEWE: x_cur = XC_sb_h_double_arrow; break;
414 case wxCURSOR_SIZENS: x_cur = XC_sb_v_double_arrow; break;
415 case wxCURSOR_POINT_LEFT: x_cur = XC_sb_left_arrow; break;
416 case wxCURSOR_POINT_RIGHT: x_cur = XC_sb_right_arrow; break;
417 // (JD Huggins) added more stock cursors for X
418 // X-only cursors BEGIN
419 case wxCURSOR_CROSS_REVERSE: x_cur = XC_cross_reverse; break;
420 case wxCURSOR_DOUBLE_ARROW: x_cur = XC_double_arrow; break;
421 case wxCURSOR_BASED_ARROW_UP: x_cur = XC_based_arrow_up; break;
422 case wxCURSOR_BASED_ARROW_DOWN: x_cur = XC_based_arrow_down; break;
423 case wxCURSOR_BLANK:
424 {
425 GC gc;
426 XGCValues gcv;
427 Pixmap empty_pixmap;
428 XColor blank_color;
429
430 empty_pixmap =
431 XCreatePixmap (dpy, RootWindow (dpy, DefaultScreen (dpy)),
432 16, 16, 1);
433 gcv.function = GXxor;
434 gc = XCreateGC (dpy,
435 empty_pixmap,
436 GCFunction,
437 &gcv);
438 XCopyArea (dpy,
439 empty_pixmap,
440 empty_pixmap,
441 gc,
442 0, 0,
443 16, 16,
444 0, 0);
445 XFreeGC (dpy, gc);
446 cursor = XCreatePixmapCursor (dpy,
447 empty_pixmap,
448 empty_pixmap,
449 &blank_color,
450 &blank_color,
451 8, 8);
452
453 break;
454 }
455 case wxCURSOR_ARROW:
456 default: x_cur = XC_top_left_arrow; break;
457 }
458
459 if( x_cur == -1 )
460 return (WXCursor)cursor;
461
462 cursor = XCreateFontCursor (dpy, x_cur);
463 return (WXCursor) cursor;
464 }
465
466 // Global cursor setting
467 void wxSetCursor(const wxCursor& WXUNUSED(cursor))
468 {
469 // Nothing to do for Motif (no global cursor)
470 }
471
472
473 // ----------------------------------------------------------------------------
474 // busy cursor stuff
475 // ----------------------------------------------------------------------------
476
477 static int wxBusyCursorCount = 0;
478
479 // Helper function
480 static void
481 wxXSetBusyCursor (wxWindow * win, wxCursor * cursor)
482 {
483 Display *display = (Display*) win->GetXDisplay();
484
485 Window xwin = (Window) win->GetXWindow();
486 if (!xwin)
487 return;
488
489 XSetWindowAttributes attrs;
490
491 if (cursor)
492 {
493 attrs.cursor = (Cursor) cursor->GetXCursor(display);
494 }
495 else
496 {
497 // Restore old cursor
498 if (win->GetCursor().Ok())
499 attrs.cursor = (Cursor) win->GetCursor().GetXCursor(display);
500 else
501 attrs.cursor = None;
502 }
503 if (xwin)
504 XChangeWindowAttributes (display, xwin, CWCursor, &attrs);
505
506 XFlush (display);
507
508 for(wxWindowList::Node *node = win->GetChildren().GetFirst (); node;
509 node = node->GetNext())
510 {
511 wxWindow *child = node->GetData ();
512 wxXSetBusyCursor (child, cursor);
513 }
514 }
515
516 // Set the cursor to the busy cursor for all windows
517 void wxBeginBusyCursor(wxCursor *cursor)
518 {
519 wxBusyCursorCount++;
520 if (wxBusyCursorCount == 1)
521 {
522 for(wxWindowList::Node *node = wxTopLevelWindows.GetFirst (); node;
523 node = node->GetNext())
524 {
525 wxWindow *win = node->GetData ();
526 wxXSetBusyCursor (win, cursor);
527 }
528 }
529 }
530
531 // Restore cursor to normal
532 void wxEndBusyCursor()
533 {
534 if (wxBusyCursorCount == 0)
535 return;
536
537 wxBusyCursorCount--;
538 if (wxBusyCursorCount == 0)
539 {
540 for(wxWindowList::Node *node = wxTopLevelWindows.GetFirst (); node;
541 node = node->GetNext())
542 {
543 wxWindow *win = node->GetData ();
544 wxXSetBusyCursor (win, NULL);
545 }
546 }
547 }
548
549 // TRUE if we're between the above two calls
550 bool wxIsBusy()
551 {
552 return (wxBusyCursorCount > 0);
553 }