]> git.saurik.com Git - wxWidgets.git/blame - src/motif/cursor.cpp
added wxDIB::Save() and wxDIB to/from wxBitmap) conversions, use them instead of...
[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
JS
17#include "wx/app.h"
18#include "wx/utils.h"
93e73c74 19#include "wx/list.h"
4daa4d66
CE
20#if wxUSE_IMAGE
21#include "wx/image.h"
22#endif
f97c9854 23
338dd992
JJ
24#ifdef __VMS__
25#pragma message disable nosimpint
26#endif
f97c9854
JS
27#include <Xm/Xm.h>
28#include <X11/cursorfont.h>
338dd992
JJ
29#ifdef __VMS__
30#pragma message enable nosimpint
31#endif
f97c9854
JS
32
33#include "wx/motif/private.h"
4bb6408c 34
93e73c74
MB
35// Cursor for one display, so we can choose the correct one for
36// the current display.
37class wxXCursor
38{
39public:
40 WXDisplay* m_display;
41 WXCursor m_cursor;
42};
43
44WX_DECLARE_LIST(wxXCursor, wxXCursorList);
45#include "wx/listimpl.cpp"
46WX_DEFINE_LIST(wxXCursorList);
47
48class WXDLLEXPORT wxCursorRefData: public wxObjectRefData
49{
50 friend class WXDLLEXPORT wxCursor;
51public:
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
62IMPLEMENT_DYNAMIC_CLASS(wxCursor, wxObject)
4bb6408c
JS
63
64wxCursorRefData::wxCursorRefData()
65{
f97c9854 66 m_cursorId = wxCURSOR_NONE;
4bb6408c
JS
67}
68
69wxCursorRefData::~wxCursorRefData()
70{
93e73c74 71 wxXCursorList::Node* node = m_cursors.GetFirst();
f97c9854
JS
72 while (node)
73 {
93e73c74
MB
74 wxXCursor* c = node->GetData();
75 XFreeCursor((Display*) c->m_display, (Cursor) c->m_cursor);
f97c9854 76 delete c;
fd304d98 77 node = node->GetNext();
f97c9854 78 }
4bb6408c
JS
79}
80
4bb6408c
JS
81wxCursor::wxCursor()
82{
83}
84
4daa4d66
CE
85#if wxUSE_IMAGE
86wxCursor::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
4daa4d66
CE
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 }
4daa4d66
CE
135 }
136 else // no mask
137 {
138 for (i=0; i<imagebitcount; i++)
139 maskBits[i] = 0xFF;
4daa4d66 140 }
4daa4d66 141
4daa4d66
CE
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);
4daa4d66 208 }
4daa4d66
CE
209}
210#endif
211
f97c9854
JS
212wxCursor::wxCursor(const char bits[], int width, int height,
213 int hotSpotX, int hotSpotY, const char maskBits[])
4bb6408c 214{
f97c9854 215 m_refData = new wxCursorRefData;
4bb6408c 216
f97c9854
JS
217 Display *dpy = (Display*) wxGetDisplay();
218 int screen_num = DefaultScreen (dpy);
4bb6408c 219
f97c9854
JS
220 Pixmap pixmap = XCreatePixmapFromBitmapData (dpy,
221 RootWindow (dpy, DefaultScreen(dpy)),
222 (char*) bits, width, height,
223 1 , 0 , 1);
4bb6408c 224
f97c9854
JS
225 Pixmap mask_pixmap = None;
226 if (maskBits != NULL)
4bb6408c 227 {
f97c9854
JS
228 mask_pixmap = XCreatePixmapFromBitmapData (dpy,
229 RootWindow (dpy, DefaultScreen(dpy)),
230 (char*) maskBits, width, height,
231 1 , 0 , 1);
4bb6408c 232 }
f97c9854
JS
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)
4bb6408c 252 {
f97c9854 253 XFreePixmap( dpy, mask_pixmap );
4bb6408c 254 }
f97c9854
JS
255
256 if (cursor)
4bb6408c 257 {
f97c9854
JS
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);
4bb6408c 263 }
f97c9854
JS
264}
265
266wxCursor::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)),
d3a80c92
MB
282 wxConstCast(name.c_str(), char),
283 &w, &h, &pixmap, &hotX, &hotY);
f97c9854 284
f97c9854
JS
285 if ((value == BitmapFileInvalid) ||
286 (value == BitmapOpenFailed) ||
287 (value == BitmapNoMemory))
4bb6408c 288 {
4bb6408c 289 }
f97c9854 290 else
4bb6408c 291 {
f97c9854
JS
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);
f97c9854 329 }
4bb6408c 330 }
f97c9854
JS
331
332}
333
334// Cursors by stock number
335wxCursor::wxCursor(wxStockCursor id)
336{
337 m_refData = new wxCursorRefData;
338 M_CURSORDATA->m_cursorId = id;
f97c9854
JS
339}
340
341wxCursor::~wxCursor()
342{
343}
344
93e73c74
MB
345bool wxCursor::Ok() const
346{
347 return m_refData != NULL;
348}
349
f97c9854
JS
350// Motif-specific: create/get a cursor for the current display
351WXCursor wxCursor::GetXCursor(WXDisplay* display)
352{
353 if (!M_CURSORDATA)
354 return (WXCursor) 0;
93e73c74 355 wxXCursorList::Node* node = M_CURSORDATA->m_cursors.GetFirst();
f97c9854 356 while (node)
4bb6408c 357 {
93e73c74 358 wxXCursor* c = node->GetData();
f97c9854
JS
359 if (c->m_display == display)
360 return c->m_cursor;
fd304d98 361 node = node->GetNext();
4bb6408c 362 }
f97c9854
JS
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)
4bb6408c 367 {
f97c9854
JS
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;
4bb6408c 379 }
4bb6408c 380
f97c9854
JS
381 // Not an id-type cursor, so we don't know how to create it.
382 return (WXCursor) 0;
4bb6408c
JS
383}
384
f97c9854
JS
385// Make a cursor from standard id
386WXCursor wxCursor::MakeCursor(WXDisplay* display, wxStockCursor id)
4bb6408c 387{
f97c9854
JS
388 Display* dpy = (Display*) display;
389 Cursor cursor = (Cursor) 0;
93e73c74 390 int x_cur = -1;
f97c9854
JS
391
392 switch (id)
393 {
93e73c74
MB
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;
f97c9854
JS
417 // (JD Huggins) added more stock cursors for X
418 // X-only cursors BEGIN
93e73c74
MB
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,
f97c9854
JS
439 empty_pixmap,
440 empty_pixmap,
441 gc,
442 0, 0,
443 16, 16,
444 0, 0);
93e73c74
MB
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;
f97c9854 457 }
93e73c74
MB
458
459 if( x_cur == -1 )
460 return (WXCursor)cursor;
461
462 cursor = XCreateFontCursor (dpy, x_cur);
f97c9854 463 return (WXCursor) cursor;
4bb6408c
JS
464}
465
466// Global cursor setting
f9e02ac7 467void wxSetCursor(const wxCursor& WXUNUSED(cursor))
4bb6408c 468{
f97c9854 469 // Nothing to do for Motif (no global cursor)
4bb6408c
JS
470}
471
472
707440dc
JS
473// ----------------------------------------------------------------------------
474// busy cursor stuff
475// ----------------------------------------------------------------------------
476
477static int wxBusyCursorCount = 0;
478
479// Helper function
480static void
481wxXSetBusyCursor (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
fd304d98
MB
508 for(wxWindowList::Node *node = win->GetChildren().GetFirst (); node;
509 node = node->GetNext())
707440dc 510 {
fd304d98 511 wxWindow *child = node->GetData ();
707440dc
JS
512 wxXSetBusyCursor (child, cursor);
513 }
514}
515
516// Set the cursor to the busy cursor for all windows
517void wxBeginBusyCursor(wxCursor *cursor)
518{
519 wxBusyCursorCount++;
520 if (wxBusyCursorCount == 1)
521 {
fd304d98
MB
522 for(wxWindowList::Node *node = wxTopLevelWindows.GetFirst (); node;
523 node = node->GetNext())
707440dc 524 {
fd304d98 525 wxWindow *win = node->GetData ();
707440dc
JS
526 wxXSetBusyCursor (win, cursor);
527 }
528 }
529}
530
531// Restore cursor to normal
532void wxEndBusyCursor()
533{
534 if (wxBusyCursorCount == 0)
535 return;
536
537 wxBusyCursorCount--;
538 if (wxBusyCursorCount == 0)
539 {
fd304d98
MB
540 for(wxWindowList::Node *node = wxTopLevelWindows.GetFirst (); node;
541 node = node->GetNext())
707440dc 542 {
fd304d98 543 wxWindow *win = node->GetData ();
707440dc
JS
544 wxXSetBusyCursor (win, NULL);
545 }
546 }
547}
548
549// TRUE if we're between the above two calls
550bool wxIsBusy()
551{
552 return (wxBusyCursorCount > 0);
553}