1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/cursor.cpp
3 // Purpose: wxCursor implementation
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
13 #include "wx/cursor.h"
16 #include "wx/window.h"
19 #include "wx/bitmap.h"
24 #include "wx/gtk/private/object.h"
25 #include "wx/gtk/private/gtk2-compat.h"
27 //-----------------------------------------------------------------------------
29 //-----------------------------------------------------------------------------
31 class wxCursorRefData
: public wxGDIRefData
35 virtual ~wxCursorRefData();
37 virtual bool IsOk() const { return m_cursor
!= NULL
; }
42 // There is no way to copy m_cursor so we can't implement a copy ctor
44 wxDECLARE_NO_COPY_CLASS(wxCursorRefData
);
47 wxCursorRefData::wxCursorRefData()
52 wxCursorRefData::~wxCursorRefData()
54 if (m_cursor
) gdk_cursor_unref( m_cursor
);
58 //-----------------------------------------------------------------------------
60 //-----------------------------------------------------------------------------
62 #define M_CURSORDATA static_cast<wxCursorRefData*>(m_refData)
64 IMPLEMENT_DYNAMIC_CLASS(wxCursor
, wxGDIObject
)
66 // used in the following two ctors
67 extern GtkWidget
*wxGetRootWindow();
75 wxCursor::wxCursor(const wxString
& cursor_file
,
77 int hotSpotX
, int hotSpotY
)
80 if (!img
.LoadFile(cursor_file
, type
))
83 // eventually set the hotspot:
84 if (!img
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
))
85 img
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
, hotSpotX
);
86 if (!img
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
))
87 img
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
, hotSpotY
);
92 wxCursor::wxCursor(const wxImage
& img
)
98 wxCursor::wxCursor(const char bits
[], int width
, int height
,
99 int hotSpotX
, int hotSpotY
,
100 const char maskBits
[], const wxColour
*fg
, const wxColour
*bg
)
102 m_refData
= new wxCursorRefData
;
103 if (hotSpotX
< 0 || hotSpotX
>= width
)
105 if (hotSpotY
< 0 || hotSpotY
>= height
)
108 wxBitmap
bitmap(bits
, width
, height
);
110 bitmap
.SetMask(new wxMask(wxBitmap(maskBits
, width
, height
)));
111 GdkPixbuf
* pixbuf
= bitmap
.GetPixbuf();
114 const int stride
= gdk_pixbuf_get_rowstride(pixbuf
);
115 const int n_channels
= gdk_pixbuf_get_n_channels(pixbuf
);
116 guchar
* data
= gdk_pixbuf_get_pixels(pixbuf
);
117 for (int j
= 0; j
< height
; j
++, data
+= stride
)
120 for (int i
= 0; i
< width
; i
++, p
+= n_channels
)
143 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixbuf(gtk_widget_get_display(wxGetRootWindow()), pixbuf
, hotSpotX
, hotSpotY
);
152 GdkBitmap
* data
= gdk_bitmap_create_from_data(
153 gtk_widget_get_window(wxGetRootWindow()), const_cast<char*>(bits
), width
, height
);
154 GdkBitmap
* mask
= gdk_bitmap_create_from_data(
155 gtk_widget_get_window(wxGetRootWindow()), const_cast<char*>(maskBits
), width
, height
);
157 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixmap(
158 data
, mask
, fg
->GetColor(), bg
->GetColor(),
159 hotSpotX
, hotSpotY
);
161 g_object_unref (data
);
162 g_object_unref (mask
);
166 wxCursor::~wxCursor()
170 void wxCursor::InitFromStock( wxStockCursor cursorId
)
172 m_refData
= new wxCursorRefData();
174 GdkCursorType gdk_cur
= GDK_LEFT_PTR
;
178 case wxCURSOR_BLANK
: gdk_cur
= GDK_BLANK_CURSOR
; break;
182 const char bits
[] = { 0 };
183 const GdkColor color
= { 0, 0, 0, 0 };
185 GdkPixmap
*pixmap
= gdk_bitmap_create_from_data(NULL
, bits
, 1, 1);
186 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixmap(pixmap
,
191 g_object_unref(pixmap
);
195 case wxCURSOR_ARROW
: // fall through to default
196 case wxCURSOR_DEFAULT
: gdk_cur
= GDK_LEFT_PTR
; break;
197 case wxCURSOR_RIGHT_ARROW
: gdk_cur
= GDK_RIGHT_PTR
; break;
198 case wxCURSOR_HAND
: gdk_cur
= GDK_HAND2
; break;
199 case wxCURSOR_CROSS
: gdk_cur
= GDK_CROSSHAIR
; break;
200 case wxCURSOR_SIZEWE
: gdk_cur
= GDK_SB_H_DOUBLE_ARROW
; break;
201 case wxCURSOR_SIZENS
: gdk_cur
= GDK_SB_V_DOUBLE_ARROW
; break;
202 case wxCURSOR_ARROWWAIT
:
204 case wxCURSOR_WATCH
: gdk_cur
= GDK_WATCH
; break;
205 case wxCURSOR_SIZING
: gdk_cur
= GDK_SIZING
; break;
206 case wxCURSOR_SPRAYCAN
: gdk_cur
= GDK_SPRAYCAN
; break;
207 case wxCURSOR_IBEAM
: gdk_cur
= GDK_XTERM
; break;
208 case wxCURSOR_PENCIL
: gdk_cur
= GDK_PENCIL
; break;
209 case wxCURSOR_NO_ENTRY
: gdk_cur
= GDK_PIRATE
; break;
210 case wxCURSOR_SIZENWSE
:
211 case wxCURSOR_SIZENESW
: gdk_cur
= GDK_FLEUR
; break;
212 case wxCURSOR_QUESTION_ARROW
: gdk_cur
= GDK_QUESTION_ARROW
; break;
213 case wxCURSOR_PAINT_BRUSH
: gdk_cur
= GDK_SPRAYCAN
; break;
214 case wxCURSOR_MAGNIFIER
: gdk_cur
= GDK_PLUS
; break;
215 case wxCURSOR_CHAR
: gdk_cur
= GDK_XTERM
; break;
216 case wxCURSOR_LEFT_BUTTON
: gdk_cur
= GDK_LEFTBUTTON
; break;
217 case wxCURSOR_MIDDLE_BUTTON
: gdk_cur
= GDK_MIDDLEBUTTON
; break;
218 case wxCURSOR_RIGHT_BUTTON
: gdk_cur
= GDK_RIGHTBUTTON
; break;
219 case wxCURSOR_BULLSEYE
: gdk_cur
= GDK_TARGET
; break;
221 case wxCURSOR_POINT_LEFT
: gdk_cur
= GDK_SB_LEFT_ARROW
; break;
222 case wxCURSOR_POINT_RIGHT
: gdk_cur
= GDK_SB_RIGHT_ARROW
; break;
224 case wxCURSOR_DOUBLE_ARROW: gdk_cur = GDK_DOUBLE_ARROW; break;
225 case wxCURSOR_CROSS_REVERSE: gdk_cur = GDK_CROSS_REVERSE; break;
226 case wxCURSOR_BASED_ARROW_UP: gdk_cur = GDK_BASED_ARROW_UP; break;
227 case wxCURSOR_BASED_ARROW_DOWN: gdk_cur = GDK_BASED_ARROW_DOWN; break;
231 wxFAIL_MSG(wxT("unsupported cursor type"));
232 // will use the standard one
236 M_CURSORDATA
->m_cursor
= gdk_cursor_new( gdk_cur
);
241 void wxCursor::InitFromImage( const wxImage
& image
)
243 const int w
= image
.GetWidth();
244 const int h
= image
.GetHeight();
245 const guchar
* alpha
= image
.GetAlpha();
246 const bool hasMask
= image
.HasMask();
247 int hotSpotX
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
);
248 int hotSpotY
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
);
249 if (hotSpotX
< 0 || hotSpotX
> w
) hotSpotX
= 0;
250 if (hotSpotY
< 0 || hotSpotY
> h
) hotSpotY
= 0;
251 GdkPixbuf
* pixbuf
= gdk_pixbuf_new_from_data(image
.GetData(), GDK_COLORSPACE_RGB
, false, 8, w
, h
, w
* 3, NULL
, NULL
);
252 if (alpha
|| hasMask
)
254 guchar r
= 0, g
= 0, b
= 0;
257 r
= image
.GetMaskRed();
258 g
= image
.GetMaskGreen();
259 b
= image
.GetMaskBlue();
261 GdkPixbuf
* pixbuf0
= pixbuf
;
262 pixbuf
= gdk_pixbuf_add_alpha(pixbuf
, hasMask
, r
, g
, b
);
263 g_object_unref(pixbuf0
);
266 guchar
* d
= gdk_pixbuf_get_pixels(pixbuf
);
267 const int stride
= gdk_pixbuf_get_rowstride(pixbuf
);
268 for (int j
= 0; j
< h
; j
++, d
+= stride
)
269 for (int i
= 0; i
< w
; i
++, alpha
++)
271 d
[4 * i
+ 3] = *alpha
;
274 m_refData
= new wxCursorRefData
;
275 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixbuf(gtk_widget_get_display(wxGetRootWindow()), pixbuf
, hotSpotX
, hotSpotY
);
276 g_object_unref(pixbuf
);
279 #endif // wxUSE_IMAGE
281 GdkCursor
*wxCursor::GetCursor() const
283 return M_CURSORDATA
->m_cursor
;
286 wxGDIRefData
*wxCursor::CreateGDIRefData() const
288 return new wxCursorRefData
;
292 wxCursor::CloneGDIRefData(const wxGDIRefData
* WXUNUSED(data
)) const
294 // TODO: We can't clone GDK cursors at the moment. To do this we'd need
295 // to remember the original data from which the cursor was created
296 // (i.e. standard cursor type or the bitmap) or use
297 // gdk_cursor_get_cursor_type() (which is in 2.22+ only) and
298 // gdk_cursor_get_image().
299 wxFAIL_MSG( wxS("Cloning cursors is not implemented in wxGTK.") );
301 return new wxCursorRefData
;
304 //-----------------------------------------------------------------------------
305 // busy cursor routines
306 //-----------------------------------------------------------------------------
308 /* Current cursor, in order to hang on to
309 * cursor handle when setting the cursor globally */
310 wxCursor g_globalCursor
;
312 static wxCursor gs_savedCursor
;
313 static int gs_busyCount
= 0;
315 const wxCursor
&wxBusyCursor::GetStoredCursor()
317 return gs_savedCursor
;
320 const wxCursor
wxBusyCursor::GetBusyCursor()
322 return wxCursor(wxCURSOR_WATCH
);
325 static void UpdateCursors(GdkDisplay
** display
)
327 wxWindowList::const_iterator i
= wxTopLevelWindows
.begin();
328 for (size_t n
= wxTopLevelWindows
.size(); n
--; ++i
)
331 win
->GTKUpdateCursor();
332 if (display
&& *display
== NULL
&& win
->m_widget
)
333 *display
= gtk_widget_get_display(win
->m_widget
);
337 void wxEndBusyCursor()
339 if (--gs_busyCount
> 0)
342 g_globalCursor
= gs_savedCursor
;
343 gs_savedCursor
= wxNullCursor
;
347 void wxBeginBusyCursor(const wxCursor
* cursor
)
349 if (gs_busyCount
++ > 0)
352 wxASSERT_MSG( !gs_savedCursor
.IsOk(),
353 wxT("forgot to call wxEndBusyCursor, will leak memory") );
355 gs_savedCursor
= g_globalCursor
;
356 g_globalCursor
= *cursor
;
357 GdkDisplay
* display
= NULL
;
358 UpdateCursors(&display
);
360 gdk_display_flush(display
);
365 return gs_busyCount
> 0;
368 void wxSetCursor( const wxCursor
& cursor
)
370 g_globalCursor
= cursor
;