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 /////////////////////////////////////////////////////////////////////////////
9 // For compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
12 #include "wx/cursor.h"
15 #include "wx/window.h"
17 #include "wx/bitmap.h"
22 #include "wx/gtk/private/object.h"
23 #include "wx/gtk/private/gtk2-compat.h"
25 //-----------------------------------------------------------------------------
27 //-----------------------------------------------------------------------------
29 class wxCursorRefData
: public wxGDIRefData
33 virtual ~wxCursorRefData();
35 virtual bool IsOk() const { return m_cursor
!= NULL
; }
40 // There is no way to copy m_cursor so we can't implement a copy ctor
42 wxDECLARE_NO_COPY_CLASS(wxCursorRefData
);
45 wxCursorRefData::wxCursorRefData()
50 wxCursorRefData::~wxCursorRefData()
55 g_object_unref(m_cursor
);
57 gdk_cursor_unref(m_cursor
);
62 //-----------------------------------------------------------------------------
64 //-----------------------------------------------------------------------------
66 #define M_CURSORDATA static_cast<wxCursorRefData*>(m_refData)
68 IMPLEMENT_DYNAMIC_CLASS(wxCursor
, wxGDIObject
)
70 // used in the following two ctors
71 extern GtkWidget
*wxGetRootWindow();
78 wxCursor::wxCursor(const wxString
& cursor_file
,
80 int hotSpotX
, int hotSpotY
)
83 if (!img
.LoadFile(cursor_file
, type
))
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
);
95 wxCursor::wxCursor(const wxImage
& img
)
101 wxCursor::wxCursor(const char bits
[], int width
, int height
,
102 int hotSpotX
, int hotSpotY
,
103 const char maskBits
[], const wxColour
*fg
, const wxColour
*bg
)
105 m_refData
= new wxCursorRefData
;
106 if (hotSpotX
< 0 || hotSpotX
>= width
)
108 if (hotSpotY
< 0 || hotSpotY
>= height
)
111 wxBitmap
bitmap(bits
, width
, height
);
113 bitmap
.SetMask(new wxMask(wxBitmap(maskBits
, width
, height
)));
114 GdkPixbuf
* pixbuf
= bitmap
.GetPixbuf();
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
)
123 for (int i
= 0; i
< width
; i
++, p
+= n_channels
)
146 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixbuf(gtk_widget_get_display(wxGetRootWindow()), pixbuf
, hotSpotX
, hotSpotY
);
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
);
160 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixmap(
161 data
, mask
, fg
->GetColor(), bg
->GetColor(),
162 hotSpotX
, hotSpotY
);
164 g_object_unref (data
);
165 g_object_unref (mask
);
169 wxCursor::~wxCursor()
173 void wxCursor::InitFromStock( wxStockCursor cursorId
)
175 m_refData
= new wxCursorRefData();
177 GdkCursorType gdk_cur
= GDK_LEFT_PTR
;
181 case wxCURSOR_BLANK
: gdk_cur
= GDK_BLANK_CURSOR
; break;
185 const char bits
[] = { 0 };
186 const GdkColor color
= { 0, 0, 0, 0 };
188 GdkPixmap
*pixmap
= gdk_bitmap_create_from_data(NULL
, bits
, 1, 1);
189 M_CURSORDATA
->m_cursor
= gdk_cursor_new_from_pixmap(pixmap
,
194 g_object_unref(pixmap
);
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
:
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;
224 case wxCURSOR_POINT_LEFT
: gdk_cur
= GDK_SB_LEFT_ARROW
; break;
225 case wxCURSOR_POINT_RIGHT
: gdk_cur
= GDK_SB_RIGHT_ARROW
; break;
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;
234 wxFAIL_MSG(wxT("unsupported cursor type"));
235 // will use the standard one
239 M_CURSORDATA
->m_cursor
= gdk_cursor_new( gdk_cur
);
244 void wxCursor::InitFromImage( const wxImage
& image
)
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
)
257 guchar r
= 0, g
= 0, b
= 0;
260 r
= image
.GetMaskRed();
261 g
= image
.GetMaskGreen();
262 b
= image
.GetMaskBlue();
264 GdkPixbuf
* pixbuf0
= pixbuf
;
265 pixbuf
= gdk_pixbuf_add_alpha(pixbuf
, hasMask
, r
, g
, b
);
266 g_object_unref(pixbuf0
);
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
++)
274 d
[4 * i
+ 3] = *alpha
;
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
);
282 #endif // wxUSE_IMAGE
284 GdkCursor
*wxCursor::GetCursor() const
286 return M_CURSORDATA
->m_cursor
;
289 wxGDIRefData
*wxCursor::CreateGDIRefData() const
291 return new wxCursorRefData
;
295 wxCursor::CloneGDIRefData(const wxGDIRefData
* WXUNUSED(data
)) const
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.") );
304 return new wxCursorRefData
;
307 //-----------------------------------------------------------------------------
308 // busy cursor routines
309 //-----------------------------------------------------------------------------
311 /* Current cursor, in order to hang on to
312 * cursor handle when setting the cursor globally */
313 wxCursor g_globalCursor
;
315 static wxCursor gs_savedCursor
;
316 static int gs_busyCount
= 0;
318 const wxCursor
&wxBusyCursor::GetStoredCursor()
320 return gs_savedCursor
;
323 const wxCursor
wxBusyCursor::GetBusyCursor()
325 return wxCursor(wxCURSOR_WATCH
);
328 static void UpdateCursors(GdkDisplay
** display
)
330 wxWindowList::const_iterator i
= wxTopLevelWindows
.begin();
331 for (size_t n
= wxTopLevelWindows
.size(); n
--; ++i
)
334 win
->GTKUpdateCursor();
335 if (display
&& *display
== NULL
&& win
->m_widget
)
336 *display
= gtk_widget_get_display(win
->m_widget
);
340 void wxEndBusyCursor()
342 if (--gs_busyCount
> 0)
345 g_globalCursor
= gs_savedCursor
;
346 gs_savedCursor
= wxNullCursor
;
350 void wxBeginBusyCursor(const wxCursor
* cursor
)
352 if (gs_busyCount
++ > 0)
355 wxASSERT_MSG( !gs_savedCursor
.IsOk(),
356 wxT("forgot to call wxEndBusyCursor, will leak memory") );
358 gs_savedCursor
= g_globalCursor
;
359 g_globalCursor
= *cursor
;
360 GdkDisplay
* display
= NULL
;
361 UpdateCursors(&display
);
363 gdk_display_flush(display
);
368 return gs_busyCount
> 0;
371 void wxSetCursor( const wxCursor
& cursor
)
373 g_globalCursor
= cursor
;