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"
18 #include "wx/bitmap.h"
23 #include "wx/gtk/private/object.h"
24 #include "wx/gtk/private/gtk2-compat.h"
26 //-----------------------------------------------------------------------------
28 //-----------------------------------------------------------------------------
30 class wxCursorRefData
: public wxGDIRefData
34 virtual ~wxCursorRefData();
36 virtual bool IsOk() const { return m_cursor
!= NULL
; }
41 // There is no way to copy m_cursor so we can't implement a copy ctor
43 wxDECLARE_NO_COPY_CLASS(wxCursorRefData
);
46 wxCursorRefData::wxCursorRefData()
51 wxCursorRefData::~wxCursorRefData()
56 g_object_unref(m_cursor
);
58 gdk_cursor_unref(m_cursor
);
63 //-----------------------------------------------------------------------------
65 //-----------------------------------------------------------------------------
67 #define M_CURSORDATA static_cast<wxCursorRefData*>(m_refData)
69 IMPLEMENT_DYNAMIC_CLASS(wxCursor
, wxGDIObject
)
71 // used in the following two ctors
72 extern GtkWidget
*wxGetRootWindow();
79 wxCursor::wxCursor(const wxString
& cursor_file
,
81 int hotSpotX
, int hotSpotY
)
84 if (!img
.LoadFile(cursor_file
, type
))
87 // eventually set the hotspot:
88 if (!img
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
))
89 img
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X
, hotSpotX
);
90 if (!img
.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
))
91 img
.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y
, hotSpotY
);
96 wxCursor::wxCursor(const wxImage
& img
)
102 wxCursor::wxCursor(const char bits
[], int width
, int height
,
103 int hotSpotX
, int hotSpotY
,
104 const char maskBits
[], const wxColour
*fg
, const wxColour
*bg
)
106 m_refData
= new wxCursorRefData
;
107 if (hotSpotX
< 0 || hotSpotX
>= width
)
109 if (hotSpotY
< 0 || hotSpotY
>= height
)
112 wxBitmap
bitmap(bits
, width
, height
);
114 bitmap
.SetMask(new wxMask(wxBitmap(maskBits
, width
, height
)));
115 GdkPixbuf
* pixbuf
= bitmap
.GetPixbuf();
118 const int stride
= gdk_pixbuf_get_rowstride(pixbuf
);
119 const int n_channels
= gdk_pixbuf_get_n_channels(pixbuf
);
120 guchar
* data
= gdk_pixbuf_get_pixels(pixbuf
);
121 for (int j
= 0; j
< height
; j
++, data
+= stride
)
124 for (int i
= 0; i
< width
; i
++, p
+= n_channels
)
147 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixbuf(gtk_widget_get_display(wxGetRootWindow()), pixbuf
, hotSpotX
, hotSpotY
);
156 GdkBitmap
* data
= gdk_bitmap_create_from_data(
157 gtk_widget_get_window(wxGetRootWindow()), const_cast<char*>(bits
), width
, height
);
158 GdkBitmap
* mask
= gdk_bitmap_create_from_data(
159 gtk_widget_get_window(wxGetRootWindow()), const_cast<char*>(maskBits
), width
, height
);
161 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixmap(
162 data
, mask
, fg
->GetColor(), bg
->GetColor(),
163 hotSpotX
, hotSpotY
);
165 g_object_unref (data
);
166 g_object_unref (mask
);
170 wxCursor::~wxCursor()
174 void wxCursor::InitFromStock( wxStockCursor cursorId
)
176 m_refData
= new wxCursorRefData();
178 GdkCursorType gdk_cur
= GDK_LEFT_PTR
;
182 case wxCURSOR_BLANK
: gdk_cur
= GDK_BLANK_CURSOR
; break;
186 const char bits
[] = { 0 };
187 const GdkColor color
= { 0, 0, 0, 0 };
189 GdkPixmap
*pixmap
= gdk_bitmap_create_from_data(NULL
, bits
, 1, 1);
190 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixmap(pixmap
,
195 g_object_unref(pixmap
);
199 case wxCURSOR_ARROW
: // fall through to default
200 case wxCURSOR_DEFAULT
: gdk_cur
= GDK_LEFT_PTR
; break;
201 case wxCURSOR_RIGHT_ARROW
: gdk_cur
= GDK_RIGHT_PTR
; break;
202 case wxCURSOR_HAND
: gdk_cur
= GDK_HAND2
; break;
203 case wxCURSOR_CROSS
: gdk_cur
= GDK_CROSSHAIR
; break;
204 case wxCURSOR_SIZEWE
: gdk_cur
= GDK_SB_H_DOUBLE_ARROW
; break;
205 case wxCURSOR_SIZENS
: gdk_cur
= GDK_SB_V_DOUBLE_ARROW
; break;
206 case wxCURSOR_ARROWWAIT
:
208 case wxCURSOR_WATCH
: gdk_cur
= GDK_WATCH
; break;
209 case wxCURSOR_SIZING
: gdk_cur
= GDK_SIZING
; break;
210 case wxCURSOR_SPRAYCAN
: gdk_cur
= GDK_SPRAYCAN
; break;
211 case wxCURSOR_IBEAM
: gdk_cur
= GDK_XTERM
; break;
212 case wxCURSOR_PENCIL
: gdk_cur
= GDK_PENCIL
; break;
213 case wxCURSOR_NO_ENTRY
: gdk_cur
= GDK_PIRATE
; break;
214 case wxCURSOR_SIZENWSE
:
215 case wxCURSOR_SIZENESW
: gdk_cur
= GDK_FLEUR
; break;
216 case wxCURSOR_QUESTION_ARROW
: gdk_cur
= GDK_QUESTION_ARROW
; break;
217 case wxCURSOR_PAINT_BRUSH
: gdk_cur
= GDK_SPRAYCAN
; break;
218 case wxCURSOR_MAGNIFIER
: gdk_cur
= GDK_PLUS
; break;
219 case wxCURSOR_CHAR
: gdk_cur
= GDK_XTERM
; break;
220 case wxCURSOR_LEFT_BUTTON
: gdk_cur
= GDK_LEFTBUTTON
; break;
221 case wxCURSOR_MIDDLE_BUTTON
: gdk_cur
= GDK_MIDDLEBUTTON
; break;
222 case wxCURSOR_RIGHT_BUTTON
: gdk_cur
= GDK_RIGHTBUTTON
; break;
223 case wxCURSOR_BULLSEYE
: gdk_cur
= GDK_TARGET
; break;
225 case wxCURSOR_POINT_LEFT
: gdk_cur
= GDK_SB_LEFT_ARROW
; break;
226 case wxCURSOR_POINT_RIGHT
: gdk_cur
= GDK_SB_RIGHT_ARROW
; break;
228 case wxCURSOR_DOUBLE_ARROW: gdk_cur = GDK_DOUBLE_ARROW; break;
229 case wxCURSOR_CROSS_REVERSE: gdk_cur = GDK_CROSS_REVERSE; break;
230 case wxCURSOR_BASED_ARROW_UP: gdk_cur = GDK_BASED_ARROW_UP; break;
231 case wxCURSOR_BASED_ARROW_DOWN: gdk_cur = GDK_BASED_ARROW_DOWN; break;
235 wxFAIL_MSG(wxT("unsupported cursor type"));
236 // will use the standard one
240 M_CURSORDATA
->m_cursor
= gdk_cursor_new( gdk_cur
);
245 void wxCursor::InitFromImage( const wxImage
& image
)
247 const int w
= image
.GetWidth();
248 const int h
= image
.GetHeight();
249 const guchar
* alpha
= image
.GetAlpha();
250 const bool hasMask
= image
.HasMask();
251 int hotSpotX
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X
);
252 int hotSpotY
= image
.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y
);
253 if (hotSpotX
< 0 || hotSpotX
> w
) hotSpotX
= 0;
254 if (hotSpotY
< 0 || hotSpotY
> h
) hotSpotY
= 0;
255 GdkPixbuf
* pixbuf
= gdk_pixbuf_new_from_data(image
.GetData(), GDK_COLORSPACE_RGB
, false, 8, w
, h
, w
* 3, NULL
, NULL
);
256 if (alpha
|| hasMask
)
258 guchar r
= 0, g
= 0, b
= 0;
261 r
= image
.GetMaskRed();
262 g
= image
.GetMaskGreen();
263 b
= image
.GetMaskBlue();
265 GdkPixbuf
* pixbuf0
= pixbuf
;
266 pixbuf
= gdk_pixbuf_add_alpha(pixbuf
, hasMask
, r
, g
, b
);
267 g_object_unref(pixbuf0
);
270 guchar
* d
= gdk_pixbuf_get_pixels(pixbuf
);
271 const int stride
= gdk_pixbuf_get_rowstride(pixbuf
);
272 for (int j
= 0; j
< h
; j
++, d
+= stride
)
273 for (int i
= 0; i
< w
; i
++, alpha
++)
275 d
[4 * i
+ 3] = *alpha
;
278 m_refData
= new wxCursorRefData
;
279 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixbuf(gtk_widget_get_display(wxGetRootWindow()), pixbuf
, hotSpotX
, hotSpotY
);
280 g_object_unref(pixbuf
);
283 #endif // wxUSE_IMAGE
285 GdkCursor
*wxCursor::GetCursor() const
287 return M_CURSORDATA
->m_cursor
;
290 wxGDIRefData
*wxCursor::CreateGDIRefData() const
292 return new wxCursorRefData
;
296 wxCursor::CloneGDIRefData(const wxGDIRefData
* WXUNUSED(data
)) const
298 // TODO: We can't clone GDK cursors at the moment. To do this we'd need
299 // to remember the original data from which the cursor was created
300 // (i.e. standard cursor type or the bitmap) or use
301 // gdk_cursor_get_cursor_type() (which is in 2.22+ only) and
302 // gdk_cursor_get_image().
303 wxFAIL_MSG( wxS("Cloning cursors is not implemented in wxGTK.") );
305 return new wxCursorRefData
;
308 //-----------------------------------------------------------------------------
309 // busy cursor routines
310 //-----------------------------------------------------------------------------
312 /* Current cursor, in order to hang on to
313 * cursor handle when setting the cursor globally */
314 wxCursor g_globalCursor
;
316 static wxCursor gs_savedCursor
;
317 static int gs_busyCount
= 0;
319 const wxCursor
&wxBusyCursor::GetStoredCursor()
321 return gs_savedCursor
;
324 const wxCursor
wxBusyCursor::GetBusyCursor()
326 return wxCursor(wxCURSOR_WATCH
);
329 static void UpdateCursors(GdkDisplay
** display
)
331 wxWindowList::const_iterator i
= wxTopLevelWindows
.begin();
332 for (size_t n
= wxTopLevelWindows
.size(); n
--; ++i
)
335 win
->GTKUpdateCursor();
336 if (display
&& *display
== NULL
&& win
->m_widget
)
337 *display
= gtk_widget_get_display(win
->m_widget
);
341 void wxEndBusyCursor()
343 if (--gs_busyCount
> 0)
346 g_globalCursor
= gs_savedCursor
;
347 gs_savedCursor
= wxNullCursor
;
351 void wxBeginBusyCursor(const wxCursor
* cursor
)
353 if (gs_busyCount
++ > 0)
356 wxASSERT_MSG( !gs_savedCursor
.IsOk(),
357 wxT("forgot to call wxEndBusyCursor, will leak memory") );
359 gs_savedCursor
= g_globalCursor
;
360 g_globalCursor
= *cursor
;
361 GdkDisplay
* display
= NULL
;
362 UpdateCursors(&display
);
364 gdk_display_flush(display
);
369 return gs_busyCount
> 0;
372 void wxSetCursor( const wxCursor
& cursor
)
374 g_globalCursor
= cursor
;