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