]> git.saurik.com Git - wxWidgets.git/blame - src/motif/cursor.cpp
refresh and flicker even more to ensure proper refresh in the resizeable dialogs
[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"
21
338dd992
JJ
22#ifdef __VMS__
23#pragma message disable nosimpint
24#endif
f97c9854
JS
25#include <Xm/Xm.h>
26#include <X11/cursorfont.h>
338dd992
JJ
27#ifdef __VMS__
28#pragma message enable nosimpint
29#endif
f97c9854
JS
30
31#include "wx/motif/private.h"
4bb6408c 32
4bb6408c 33IMPLEMENT_DYNAMIC_CLASS(wxCursor, wxBitmap)
f97c9854 34IMPLEMENT_DYNAMIC_CLASS(wxXCursor, wxObject)
4bb6408c
JS
35
36wxCursorRefData::wxCursorRefData()
37{
38 m_width = 32; m_height = 32;
f97c9854 39 m_cursorId = wxCURSOR_NONE;
4bb6408c
JS
40}
41
42wxCursorRefData::~wxCursorRefData()
43{
f97c9854
JS
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 }
4bb6408c
JS
53}
54
4bb6408c
JS
55wxCursor::wxCursor()
56{
57}
58
f97c9854
JS
59wxCursor::wxCursor(const char bits[], int width, int height,
60 int hotSpotX, int hotSpotY, const char maskBits[])
4bb6408c 61{
f97c9854 62 m_refData = new wxCursorRefData;
4bb6408c 63
f97c9854
JS
64 Display *dpy = (Display*) wxGetDisplay();
65 int screen_num = DefaultScreen (dpy);
4bb6408c 66
f97c9854
JS
67 Pixmap pixmap = XCreatePixmapFromBitmapData (dpy,
68 RootWindow (dpy, DefaultScreen(dpy)),
69 (char*) bits, width, height,
70 1 , 0 , 1);
4bb6408c 71
f97c9854
JS
72 Pixmap mask_pixmap = None;
73 if (maskBits != NULL)
4bb6408c 74 {
f97c9854
JS
75 mask_pixmap = XCreatePixmapFromBitmapData (dpy,
76 RootWindow (dpy, DefaultScreen(dpy)),
77 (char*) maskBits, width, height,
78 1 , 0 , 1);
4bb6408c 79 }
f97c9854
JS
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)
4bb6408c 99 {
f97c9854 100 XFreePixmap( dpy, mask_pixmap );
4bb6408c 101 }
f97c9854
JS
102
103 if (cursor)
4bb6408c 104 {
f97c9854
JS
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;
4bb6408c 111 }
f97c9854 112 else
4bb6408c 113 {
f97c9854 114 M_CURSORDATA->m_ok = TRUE;
4bb6408c 115 }
f97c9854
JS
116}
117
118wxCursor::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))
4bb6408c 143 {
4bb6408c 144 }
f97c9854 145 else
4bb6408c 146 {
f97c9854
JS
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 }
4bb6408c 186 }
f97c9854
JS
187
188}
189
190// Cursors by stock number
191wxCursor::wxCursor(wxStockCursor id)
192{
193 m_refData = new wxCursorRefData;
194 M_CURSORDATA->m_cursorId = id;
47bc1060 195 M_CURSORDATA->m_ok = TRUE;
f97c9854 196
47bc1060
JS
197 WXDisplay* display = wxGetDisplay();
198 if (!display)
199 return;
200
201 WXCursor cursor = GetXCursor(display);
f97c9854 202 if (cursor)
4bb6408c 203 {
f97c9854
JS
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;
4bb6408c 209 }
f97c9854
JS
210}
211
212wxCursor::~wxCursor()
213{
214}
215
216// Motif-specific: create/get a cursor for the current display
217WXCursor wxCursor::GetXCursor(WXDisplay* display)
218{
219 if (!M_CURSORDATA)
220 return (WXCursor) 0;
221 wxNode* node = M_CURSORDATA->m_cursors.First();
222 while (node)
4bb6408c 223 {
f97c9854
JS
224 wxXCursor* c = (wxXCursor*) node->Data();
225 if (c->m_display == display)
226 return c->m_cursor;
227 node = node->Next();
4bb6408c 228 }
f97c9854
JS
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)
4bb6408c 233 {
f97c9854
JS
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;
4bb6408c 245 }
4bb6408c 246
f97c9854
JS
247 // Not an id-type cursor, so we don't know how to create it.
248 return (WXCursor) 0;
4bb6408c
JS
249}
250
f97c9854
JS
251// Make a cursor from standard id
252WXCursor wxCursor::MakeCursor(WXDisplay* display, wxStockCursor id)
4bb6408c 253{
f97c9854
JS
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;
4bb6408c
JS
432}
433
434// Global cursor setting
f9e02ac7 435void wxSetCursor(const wxCursor& WXUNUSED(cursor))
4bb6408c 436{
f97c9854 437 // Nothing to do for Motif (no global cursor)
4bb6408c
JS
438}
439
440
707440dc
JS
441// ----------------------------------------------------------------------------
442// busy cursor stuff
443// ----------------------------------------------------------------------------
444
445static int wxBusyCursorCount = 0;
446
447// Helper function
448static void
449wxXSetBusyCursor (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
484void 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
498void 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
515bool wxIsBusy()
516{
517 return (wxBusyCursorCount > 0);
518}