]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/cursor.cpp
Fix for #15224: wxRichTextTable: Setting a cell's text colour affects subsequent...
[wxWidgets.git] / src / gtk / cursor.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
670f9935 2// Name: src/gtk/cursor.cpp
d6764050 3// Purpose: wxCursor implementation
c801d85f 4// Author: Robert Roebling
01111366 5// Copyright: (c) 1998 Robert Roebling
65571936 6// Licence: wxWindows licence
c801d85f
KB
7/////////////////////////////////////////////////////////////////////////////
8
14f355c2
VS
9// For compilers that support precompilation, includes "wx.h".
10#include "wx/wxprec.h"
11
c801d85f 12#include "wx/cursor.h"
670f9935
WS
13
14#ifndef WX_PRECOMP
df8d50a0 15 #include "wx/window.h"
0416c418 16 #include "wx/image.h"
88051436 17 #include "wx/bitmap.h"
cfaf8bd1 18 #include "wx/log.h"
670f9935
WS
19#endif // WX_PRECOMP
20
a1abca32 21#include <gtk/gtk.h>
833fb475 22#include "wx/gtk/private/object.h"
385e8575 23#include "wx/gtk/private/gtk2-compat.h"
84833214 24
c801d85f 25//-----------------------------------------------------------------------------
d6764050 26// wxCursorRefData
c801d85f
KB
27//-----------------------------------------------------------------------------
28
8f884a0d 29class wxCursorRefData: public wxGDIRefData
c801d85f 30{
8f884a0d 31public:
8bbe427f 32 wxCursorRefData();
d3c7fc99 33 virtual ~wxCursorRefData();
8bbe427f 34
8f884a0d
VZ
35 virtual bool IsOk() const { return m_cursor != NULL; }
36
c801d85f 37 GdkCursor *m_cursor;
51bf928d
VZ
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);
c801d85f
KB
43};
44
8bbe427f 45wxCursorRefData::wxCursorRefData()
c801d85f 46{
d3b9f782 47 m_cursor = NULL;
ff7b1510 48}
c801d85f 49
8bbe427f 50wxCursorRefData::~wxCursorRefData()
c801d85f 51{
5e1f70e1
PC
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 }
ff7b1510 60}
c801d85f 61
d6764050
FM
62//-----------------------------------------------------------------------------
63// wxCursor
c801d85f
KB
64//-----------------------------------------------------------------------------
65
5c33522f 66#define M_CURSORDATA static_cast<wxCursorRefData*>(m_refData)
c801d85f 67
0c0f973f 68IMPLEMENT_DYNAMIC_CLASS(wxCursor, wxGDIObject)
c801d85f 69
d6764050
FM
70// used in the following two ctors
71extern GtkWidget *wxGetRootWindow();
72
8bbe427f 73wxCursor::wxCursor()
c801d85f 74{
ff7b1510 75}
c801d85f 76
d6764050
FM
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;
03647350 85
d6764050 86 // eventually set the hotspot:
a4afdcf3 87 if (!img.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X))
d6764050 88 img.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, hotSpotX);
a4afdcf3 89 if (!img.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y))
d6764050 90 img.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, hotSpotY);
03647350 91
d6764050
FM
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{
9dc44eff
PC
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
d6764050
FM
148 if (!maskBits)
149 maskBits = bits;
150 if (!fg)
151 fg = wxBLACK;
152 if (!bg)
153 bg = wxWHITE;
d6764050 154
385e8575
PC
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);
d6764050 159
d6764050
FM
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);
9dc44eff 166#endif
d6764050
FM
167}
168
169wxCursor::~wxCursor()
170{
171}
172
0ef5b1da 173void wxCursor::InitFromStock( wxStockCursor cursorId )
c801d85f 174{
2d17d68f
RR
175 m_refData = new wxCursorRefData();
176
177 GdkCursorType gdk_cur = GDK_LEFT_PTR;
178 switch (cursorId)
179 {
9dc44eff
PC
180#ifdef __WXGTK3__
181 case wxCURSOR_BLANK: gdk_cur = GDK_BLANK_CURSOR; break;
182#else
76471ff7
VZ
183 case wxCURSOR_BLANK:
184 {
0c0f973f
PC
185 const char bits[] = { 0 };
186 const GdkColor color = { 0, 0, 0, 0 };
76471ff7
VZ
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);
0c0f973f 194 g_object_unref(pixmap);
76471ff7
VZ
195 }
196 return;
9dc44eff 197#endif
15dadf31 198 case wxCURSOR_ARROW: // fall through to default
f7bdcdd7 199 case wxCURSOR_DEFAULT: gdk_cur = GDK_LEFT_PTR; break;
15dadf31 200 case wxCURSOR_RIGHT_ARROW: gdk_cur = GDK_RIGHT_PTR; break;
6e63b5c9 201 case wxCURSOR_HAND: gdk_cur = GDK_HAND2; break;
2d17d68f
RR
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;
83f96286 205 case wxCURSOR_ARROWWAIT:
7c39369e 206 case wxCURSOR_WAIT:
2d17d68f 207 case wxCURSOR_WATCH: gdk_cur = GDK_WATCH; break;
57b10cb4 208 case wxCURSOR_SIZING: gdk_cur = GDK_SIZING; break;
2d17d68f
RR
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;
7c39369e 213 case wxCURSOR_SIZENWSE:
2d17d68f
RR
214 case wxCURSOR_SIZENESW: gdk_cur = GDK_FLEUR; break;
215 case wxCURSOR_QUESTION_ARROW: gdk_cur = GDK_QUESTION_ARROW; break;
7c39369e
VZ
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;
2d17d68f
RR
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;
13971833
RD
222 case wxCURSOR_BULLSEYE: gdk_cur = GDK_TARGET; break;
223
957d856c
VZ
224 case wxCURSOR_POINT_LEFT: gdk_cur = GDK_SB_LEFT_ARROW; break;
225 case wxCURSOR_POINT_RIGHT: gdk_cur = GDK_SB_RIGHT_ARROW; break;
c801d85f 226/*
7c39369e
VZ
227 case wxCURSOR_DOUBLE_ARROW: gdk_cur = GDK_DOUBLE_ARROW; break;
228 case wxCURSOR_CROSS_REVERSE: gdk_cur = GDK_CROSS_REVERSE; break;
2d17d68f
RR
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;
c801d85f 231*/
76471ff7 232
7c39369e 233 default:
223d09f6 234 wxFAIL_MSG(wxT("unsupported cursor type"));
7c39369e 235 // will use the standard one
7c39369e 236 break;
2d17d68f 237 }
8bbe427f 238
2d17d68f 239 M_CURSORDATA->m_cursor = gdk_cursor_new( gdk_cur );
ff7b1510 240}
c801d85f 241
7eff657c 242#if wxUSE_IMAGE
0fc5dbf5 243
d6764050 244void wxCursor::InitFromImage( const wxImage & image )
7eff657c 245{
9dc44eff
PC
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)
9f556d1d 256 {
9dc44eff
PC
257 guchar r = 0, g = 0, b = 0;
258 if (hasMask)
833fb475 259 {
9dc44eff
PC
260 r = image.GetMaskRed();
261 g = image.GetMaskGreen();
262 b = image.GetMaskBlue();
833fb475 263 }
9dc44eff
PC
264 GdkPixbuf* pixbuf0 = pixbuf;
265 pixbuf = gdk_pixbuf_add_alpha(pixbuf, hasMask, r, g, b);
266 g_object_unref(pixbuf0);
267 if (alpha)
7eff657c 268 {
9dc44eff
PC
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;
833fb475 275 }
833fb475 276 }
9dc44eff
PC
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);
7eff657c 280}
0fc5dbf5
VZ
281
282#endif // wxUSE_IMAGE
7eff657c 283
8f884a0d 284GdkCursor *wxCursor::GetCursor() const
c801d85f 285{
8f884a0d 286 return M_CURSORDATA->m_cursor;
ff7b1510 287}
c801d85f 288
8f884a0d 289wxGDIRefData *wxCursor::CreateGDIRefData() const
c801d85f 290{
8f884a0d
VZ
291 return new wxCursorRefData;
292}
293
51bf928d
VZ
294wxGDIRefData *
295wxCursor::CloneGDIRefData(const wxGDIRefData * WXUNUSED(data)) const
8f884a0d 296{
51bf928d
VZ
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;
ff7b1510 305}
c801d85f
KB
306
307//-----------------------------------------------------------------------------
308// busy cursor routines
309//-----------------------------------------------------------------------------
310
b541538f
PC
311/* Current cursor, in order to hang on to
312 * cursor handle when setting the cursor globally */
313wxCursor g_globalCursor;
7c39369e 314
238d735d 315static wxCursor gs_savedCursor;
89a43902 316static int gs_busyCount = 0;
c801d85f 317
f6bcfd97
BP
318const wxCursor &wxBusyCursor::GetStoredCursor()
319{
320 return gs_savedCursor;
321}
322
323const wxCursor wxBusyCursor::GetBusyCursor()
324{
325 return wxCursor(wxCURSOR_WATCH);
326}
327
2e952cd1 328static void UpdateCursors(GdkDisplay** display)
df8d50a0 329{
2e952cd1
PC
330 wxWindowList::const_iterator i = wxTopLevelWindows.begin();
331 for (size_t n = wxTopLevelWindows.size(); n--; ++i)
df8d50a0
PC
332 {
333 wxWindow* win = *i;
2e952cd1
PC
334 win->GTKUpdateCursor();
335 if (display && *display == NULL && win->m_widget)
336 *display = gtk_widget_get_display(win->m_widget);
df8d50a0
PC
337 }
338}
339
8bbe427f 340void wxEndBusyCursor()
c801d85f 341{
238d735d 342 if (--gs_busyCount > 0)
89a43902
VZ
343 return;
344
df8d50a0 345 g_globalCursor = gs_savedCursor;
238d735d 346 gs_savedCursor = wxNullCursor;
2e952cd1 347 UpdateCursors(NULL);
ff7b1510 348}
c801d85f 349
df8d50a0 350void wxBeginBusyCursor(const wxCursor* cursor)
c801d85f 351{
238d735d 352 if (gs_busyCount++ > 0)
89a43902
VZ
353 return;
354
a1b806b9 355 wxASSERT_MSG( !gs_savedCursor.IsOk(),
223d09f6 356 wxT("forgot to call wxEndBusyCursor, will leak memory") );
7c39369e 357
238d735d 358 gs_savedCursor = g_globalCursor;
df8d50a0
PC
359 g_globalCursor = *cursor;
360 GdkDisplay* display = NULL;
2e952cd1 361 UpdateCursors(&display);
df8d50a0
PC
362 if (display)
363 gdk_display_flush(display);
ff7b1510 364}
c801d85f 365
8bbe427f 366bool wxIsBusy()
c801d85f 367{
89a43902 368 return gs_busyCount > 0;
ff7b1510 369}
c801d85f
KB
370
371void wxSetCursor( const wxCursor& cursor )
372{
238d735d 373 g_globalCursor = cursor;
2e952cd1 374 UpdateCursors(NULL);
ff7b1510 375}