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