]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk/cursor.cpp
Propagate the event handling fixes to wxVarScrollHelperBase.
[wxWidgets.git] / src / gtk / cursor.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/gtk/cursor.cpp
3// Purpose: wxCursor implementation
4// Author: Robert Roebling
5// Copyright: (c) 1998 Robert Roebling
6// Licence: wxWindows licence
7/////////////////////////////////////////////////////////////////////////////
8
9// For compilers that support precompilation, includes "wx.h".
10#include "wx/wxprec.h"
11
12#include "wx/cursor.h"
13
14#ifndef WX_PRECOMP
15 #include "wx/window.h"
16 #include "wx/image.h"
17 #include "wx/bitmap.h"
18 #include "wx/log.h"
19#endif // WX_PRECOMP
20
21#include <gtk/gtk.h>
22#include "wx/gtk/private/object.h"
23#include "wx/gtk/private/gtk2-compat.h"
24
25//-----------------------------------------------------------------------------
26// wxCursorRefData
27//-----------------------------------------------------------------------------
28
29class wxCursorRefData: public wxGDIRefData
30{
31public:
32 wxCursorRefData();
33 virtual ~wxCursorRefData();
34
35 virtual bool IsOk() const { return m_cursor != NULL; }
36
37 GdkCursor *m_cursor;
38
39private:
40 // There is no way to copy m_cursor so we can't implement a copy ctor
41 // properly.
42 wxDECLARE_NO_COPY_CLASS(wxCursorRefData);
43};
44
45wxCursorRefData::wxCursorRefData()
46{
47 m_cursor = NULL;
48}
49
50wxCursorRefData::~wxCursorRefData()
51{
52 if (m_cursor)
53 {
54#ifdef __WXGTK3__
55 g_object_unref(m_cursor);
56#else
57 gdk_cursor_unref(m_cursor);
58#endif
59 }
60}
61
62//-----------------------------------------------------------------------------
63// wxCursor
64//-----------------------------------------------------------------------------
65
66#define M_CURSORDATA static_cast<wxCursorRefData*>(m_refData)
67
68IMPLEMENT_DYNAMIC_CLASS(wxCursor, wxGDIObject)
69
70// used in the following two ctors
71extern GtkWidget *wxGetRootWindow();
72
73wxCursor::wxCursor()
74{
75}
76
77#if wxUSE_IMAGE
78wxCursor::wxCursor(const wxString& cursor_file,
79 wxBitmapType type,
80 int hotSpotX, int hotSpotY)
81{
82 wxImage img;
83 if (!img.LoadFile(cursor_file, type))
84 return;
85
86 // eventually set the hotspot:
87 if (!img.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X))
88 img.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, hotSpotX);
89 if (!img.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y))
90 img.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, hotSpotY);
91
92 InitFromImage(img);
93}
94
95wxCursor::wxCursor(const wxImage& img)
96{
97 InitFromImage(img);
98}
99#endif
100
101wxCursor::wxCursor(const char bits[], int width, int height,
102 int hotSpotX, int hotSpotY,
103 const char maskBits[], const wxColour *fg, const wxColour *bg)
104{
105 m_refData = new wxCursorRefData;
106 if (hotSpotX < 0 || hotSpotX >= width)
107 hotSpotX = 0;
108 if (hotSpotY < 0 || hotSpotY >= height)
109 hotSpotY = 0;
110#ifdef __WXGTK3__
111 wxBitmap bitmap(bits, width, height);
112 if (maskBits)
113 bitmap.SetMask(new wxMask(wxBitmap(maskBits, width, height)));
114 GdkPixbuf* pixbuf = bitmap.GetPixbuf();
115 if (fg || bg)
116 {
117 const int stride = gdk_pixbuf_get_rowstride(pixbuf);
118 const int n_channels = gdk_pixbuf_get_n_channels(pixbuf);
119 guchar* data = gdk_pixbuf_get_pixels(pixbuf);
120 for (int j = 0; j < height; j++, data += stride)
121 {
122 guchar* p = data;
123 for (int i = 0; i < width; i++, p += n_channels)
124 {
125 if (p[0])
126 {
127 if (fg)
128 {
129 p[0] = fg->Red();
130 p[1] = fg->Green();
131 p[2] = fg->Blue();
132 }
133 }
134 else
135 {
136 if (bg)
137 {
138 p[0] = bg->Red();
139 p[1] = bg->Green();
140 p[2] = bg->Blue();
141 }
142 }
143 }
144 }
145 }
146 M_CURSORDATA->m_cursor = gdk_cursor_new_from_pixbuf(gtk_widget_get_display(wxGetRootWindow()), pixbuf, hotSpotX, hotSpotY);
147#else
148 if (!maskBits)
149 maskBits = bits;
150 if (!fg)
151 fg = wxBLACK;
152 if (!bg)
153 bg = wxWHITE;
154
155 GdkBitmap* data = gdk_bitmap_create_from_data(
156 gtk_widget_get_window(wxGetRootWindow()), const_cast<char*>(bits), width, height);
157 GdkBitmap* mask = gdk_bitmap_create_from_data(
158 gtk_widget_get_window(wxGetRootWindow()), const_cast<char*>(maskBits), width, height);
159
160 M_CURSORDATA->m_cursor = gdk_cursor_new_from_pixmap(
161 data, mask, fg->GetColor(), bg->GetColor(),
162 hotSpotX, hotSpotY );
163
164 g_object_unref (data);
165 g_object_unref (mask);
166#endif
167}
168
169wxCursor::~wxCursor()
170{
171}
172
173void wxCursor::InitFromStock( wxStockCursor cursorId )
174{
175 m_refData = new wxCursorRefData();
176
177 GdkCursorType gdk_cur = GDK_LEFT_PTR;
178 switch (cursorId)
179 {
180#ifdef __WXGTK3__
181 case wxCURSOR_BLANK: gdk_cur = GDK_BLANK_CURSOR; break;
182#else
183 case wxCURSOR_BLANK:
184 {
185 const char bits[] = { 0 };
186 const GdkColor color = { 0, 0, 0, 0 };
187
188 GdkPixmap *pixmap = gdk_bitmap_create_from_data(NULL, bits, 1, 1);
189 M_CURSORDATA->m_cursor = gdk_cursor_new_from_pixmap(pixmap,
190 pixmap,
191 &color,
192 &color,
193 0, 0);
194 g_object_unref(pixmap);
195 }
196 return;
197#endif
198 case wxCURSOR_ARROW: // fall through to default
199 case wxCURSOR_DEFAULT: gdk_cur = GDK_LEFT_PTR; break;
200 case wxCURSOR_RIGHT_ARROW: gdk_cur = GDK_RIGHT_PTR; break;
201 case wxCURSOR_HAND: gdk_cur = GDK_HAND2; break;
202 case wxCURSOR_CROSS: gdk_cur = GDK_CROSSHAIR; break;
203 case wxCURSOR_SIZEWE: gdk_cur = GDK_SB_H_DOUBLE_ARROW; break;
204 case wxCURSOR_SIZENS: gdk_cur = GDK_SB_V_DOUBLE_ARROW; break;
205 case wxCURSOR_ARROWWAIT:
206 case wxCURSOR_WAIT:
207 case wxCURSOR_WATCH: gdk_cur = GDK_WATCH; break;
208 case wxCURSOR_SIZING: gdk_cur = GDK_SIZING; break;
209 case wxCURSOR_SPRAYCAN: gdk_cur = GDK_SPRAYCAN; break;
210 case wxCURSOR_IBEAM: gdk_cur = GDK_XTERM; break;
211 case wxCURSOR_PENCIL: gdk_cur = GDK_PENCIL; break;
212 case wxCURSOR_NO_ENTRY: gdk_cur = GDK_PIRATE; break;
213 case wxCURSOR_SIZENWSE:
214 case wxCURSOR_SIZENESW: gdk_cur = GDK_FLEUR; break;
215 case wxCURSOR_QUESTION_ARROW: gdk_cur = GDK_QUESTION_ARROW; break;
216 case wxCURSOR_PAINT_BRUSH: gdk_cur = GDK_SPRAYCAN; break;
217 case wxCURSOR_MAGNIFIER: gdk_cur = GDK_PLUS; break;
218 case wxCURSOR_CHAR: gdk_cur = GDK_XTERM; break;
219 case wxCURSOR_LEFT_BUTTON: gdk_cur = GDK_LEFTBUTTON; break;
220 case wxCURSOR_MIDDLE_BUTTON: gdk_cur = GDK_MIDDLEBUTTON; break;
221 case wxCURSOR_RIGHT_BUTTON: gdk_cur = GDK_RIGHTBUTTON; break;
222 case wxCURSOR_BULLSEYE: gdk_cur = GDK_TARGET; break;
223
224 case wxCURSOR_POINT_LEFT: gdk_cur = GDK_SB_LEFT_ARROW; break;
225 case wxCURSOR_POINT_RIGHT: gdk_cur = GDK_SB_RIGHT_ARROW; break;
226/*
227 case wxCURSOR_DOUBLE_ARROW: gdk_cur = GDK_DOUBLE_ARROW; break;
228 case wxCURSOR_CROSS_REVERSE: gdk_cur = GDK_CROSS_REVERSE; break;
229 case wxCURSOR_BASED_ARROW_UP: gdk_cur = GDK_BASED_ARROW_UP; break;
230 case wxCURSOR_BASED_ARROW_DOWN: gdk_cur = GDK_BASED_ARROW_DOWN; break;
231*/
232
233 default:
234 wxFAIL_MSG(wxT("unsupported cursor type"));
235 // will use the standard one
236 break;
237 }
238
239 M_CURSORDATA->m_cursor = gdk_cursor_new( gdk_cur );
240}
241
242#if wxUSE_IMAGE
243
244void wxCursor::InitFromImage( const wxImage & image )
245{
246 const int w = image.GetWidth();
247 const int h = image.GetHeight();
248 const guchar* alpha = image.GetAlpha();
249 const bool hasMask = image.HasMask();
250 int hotSpotX = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X);
251 int hotSpotY = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y);
252 if (hotSpotX < 0 || hotSpotX > w) hotSpotX = 0;
253 if (hotSpotY < 0 || hotSpotY > h) hotSpotY = 0;
254 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(image.GetData(), GDK_COLORSPACE_RGB, false, 8, w, h, w * 3, NULL, NULL);
255 if (alpha || hasMask)
256 {
257 guchar r = 0, g = 0, b = 0;
258 if (hasMask)
259 {
260 r = image.GetMaskRed();
261 g = image.GetMaskGreen();
262 b = image.GetMaskBlue();
263 }
264 GdkPixbuf* pixbuf0 = pixbuf;
265 pixbuf = gdk_pixbuf_add_alpha(pixbuf, hasMask, r, g, b);
266 g_object_unref(pixbuf0);
267 if (alpha)
268 {
269 guchar* d = gdk_pixbuf_get_pixels(pixbuf);
270 const int stride = gdk_pixbuf_get_rowstride(pixbuf);
271 for (int j = 0; j < h; j++, d += stride)
272 for (int i = 0; i < w; i++, alpha++)
273 if (d[4 * i + 3])
274 d[4 * i + 3] = *alpha;
275 }
276 }
277 m_refData = new wxCursorRefData;
278 M_CURSORDATA->m_cursor = gdk_cursor_new_from_pixbuf(gtk_widget_get_display(wxGetRootWindow()), pixbuf, hotSpotX, hotSpotY);
279 g_object_unref(pixbuf);
280}
281
282#endif // wxUSE_IMAGE
283
284GdkCursor *wxCursor::GetCursor() const
285{
286 return M_CURSORDATA->m_cursor;
287}
288
289wxGDIRefData *wxCursor::CreateGDIRefData() const
290{
291 return new wxCursorRefData;
292}
293
294wxGDIRefData *
295wxCursor::CloneGDIRefData(const wxGDIRefData * WXUNUSED(data)) const
296{
297 // TODO: We can't clone GDK cursors at the moment. To do this we'd need
298 // to remember the original data from which the cursor was created
299 // (i.e. standard cursor type or the bitmap) or use
300 // gdk_cursor_get_cursor_type() (which is in 2.22+ only) and
301 // gdk_cursor_get_image().
302 wxFAIL_MSG( wxS("Cloning cursors is not implemented in wxGTK.") );
303
304 return new wxCursorRefData;
305}
306
307//-----------------------------------------------------------------------------
308// busy cursor routines
309//-----------------------------------------------------------------------------
310
311/* Current cursor, in order to hang on to
312 * cursor handle when setting the cursor globally */
313wxCursor g_globalCursor;
314
315static wxCursor gs_savedCursor;
316static int gs_busyCount = 0;
317
318const wxCursor &wxBusyCursor::GetStoredCursor()
319{
320 return gs_savedCursor;
321}
322
323const wxCursor wxBusyCursor::GetBusyCursor()
324{
325 return wxCursor(wxCURSOR_WATCH);
326}
327
328static void UpdateCursors(GdkDisplay** display)
329{
330 wxWindowList::const_iterator i = wxTopLevelWindows.begin();
331 for (size_t n = wxTopLevelWindows.size(); n--; ++i)
332 {
333 wxWindow* win = *i;
334 win->GTKUpdateCursor();
335 if (display && *display == NULL && win->m_widget)
336 *display = gtk_widget_get_display(win->m_widget);
337 }
338}
339
340void wxEndBusyCursor()
341{
342 if (--gs_busyCount > 0)
343 return;
344
345 g_globalCursor = gs_savedCursor;
346 gs_savedCursor = wxNullCursor;
347 UpdateCursors(NULL);
348}
349
350void wxBeginBusyCursor(const wxCursor* cursor)
351{
352 if (gs_busyCount++ > 0)
353 return;
354
355 wxASSERT_MSG( !gs_savedCursor.IsOk(),
356 wxT("forgot to call wxEndBusyCursor, will leak memory") );
357
358 gs_savedCursor = g_globalCursor;
359 g_globalCursor = *cursor;
360 GdkDisplay* display = NULL;
361 UpdateCursors(&display);
362 if (display)
363 gdk_display_flush(display);
364}
365
366bool wxIsBusy()
367{
368 return gs_busyCount > 0;
369}
370
371void wxSetCursor( const wxCursor& cursor )
372{
373 g_globalCursor = cursor;
374 UpdateCursors(NULL);
375}