]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/cursor.cpp
Cleanly separate GUI socket-related code from net library.
[wxWidgets.git] / src / gtk1 / cursor.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
670f9935 2// Name: src/gtk1/cursor.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
dbf858b5 5// Id: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling
65571936 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
c801d85f 13#include "wx/cursor.h"
670f9935
WS
14
15#ifndef WX_PRECOMP
16 #include "wx/app.h"
de6185e2 17 #include "wx/utils.h"
670f9935
WS
18#endif // WX_PRECOMP
19
071a2d78 20#include <gdk/gdk.h>
a1db952f 21#include <gtk/gtk.h>
83624f79 22
238d735d
RR
23//-----------------------------------------------------------------------------
24// idle system
25//-----------------------------------------------------------------------------
26
27extern void wxapp_install_idle_handler();
28extern bool g_isIdle;
29
c801d85f
KB
30//-----------------------------------------------------------------------------
31// wxCursor
32//-----------------------------------------------------------------------------
33
8f884a0d 34class wxCursorRefData : public wxGDIRefData
c801d85f 35{
8f884a0d 36public:
8bbe427f 37 wxCursorRefData();
d3c7fc99 38 virtual ~wxCursorRefData();
8bbe427f 39
c801d85f
KB
40 GdkCursor *m_cursor;
41};
42
8bbe427f 43wxCursorRefData::wxCursorRefData()
c801d85f 44{
d3b9f782 45 m_cursor = NULL;
ff7b1510 46}
c801d85f 47
8bbe427f 48wxCursorRefData::~wxCursorRefData()
c801d85f 49{
2d17d68f 50 if (m_cursor) gdk_cursor_destroy( m_cursor );
ff7b1510 51}
c801d85f
KB
52
53//-----------------------------------------------------------------------------
54
55#define M_CURSORDATA ((wxCursorRefData *)m_refData)
56
57IMPLEMENT_DYNAMIC_CLASS(wxCursor,wxObject)
58
8bbe427f 59wxCursor::wxCursor()
c801d85f 60{
7eff657c 61
ff7b1510 62}
c801d85f 63
0ef5b1da 64void wxCursor::InitFromStock( wxStockCursor cursorId )
c801d85f 65{
2d17d68f
RR
66 m_refData = new wxCursorRefData();
67
68 GdkCursorType gdk_cur = GDK_LEFT_PTR;
69 switch (cursorId)
70 {
76471ff7
VZ
71 case wxCURSOR_BLANK:
72 {
73 static const gchar bits[] = { 0 };
defdd888 74 static /* const -- not in GTK1 */ GdkColor color = { 0, 0, 0, 0 };
76471ff7
VZ
75
76 GdkPixmap *pixmap = gdk_bitmap_create_from_data(NULL, bits, 1, 1);
77 M_CURSORDATA->m_cursor = gdk_cursor_new_from_pixmap(pixmap,
78 pixmap,
79 &color,
80 &color,
81 0, 0);
82 }
83 return;
84
15dadf31 85 case wxCURSOR_ARROW: // fall through to default
f7bdcdd7 86 case wxCURSOR_DEFAULT: gdk_cur = GDK_LEFT_PTR; break;
15dadf31 87 case wxCURSOR_RIGHT_ARROW: gdk_cur = GDK_RIGHT_PTR; break;
2d17d68f
RR
88 case wxCURSOR_HAND: gdk_cur = GDK_HAND1; break;
89 case wxCURSOR_CROSS: gdk_cur = GDK_CROSSHAIR; break;
90 case wxCURSOR_SIZEWE: gdk_cur = GDK_SB_H_DOUBLE_ARROW; break;
91 case wxCURSOR_SIZENS: gdk_cur = GDK_SB_V_DOUBLE_ARROW; break;
83f96286 92 case wxCURSOR_ARROWWAIT:
7c39369e 93 case wxCURSOR_WAIT:
2d17d68f
RR
94 case wxCURSOR_WATCH: gdk_cur = GDK_WATCH; break;
95 case wxCURSOR_SIZING: gdk_cur = GDK_SIZING; break;
96 case wxCURSOR_SPRAYCAN: gdk_cur = GDK_SPRAYCAN; break;
97 case wxCURSOR_IBEAM: gdk_cur = GDK_XTERM; break;
98 case wxCURSOR_PENCIL: gdk_cur = GDK_PENCIL; break;
99 case wxCURSOR_NO_ENTRY: gdk_cur = GDK_PIRATE; break;
7c39369e 100 case wxCURSOR_SIZENWSE:
2d17d68f
RR
101 case wxCURSOR_SIZENESW: gdk_cur = GDK_FLEUR; break;
102 case wxCURSOR_QUESTION_ARROW: gdk_cur = GDK_QUESTION_ARROW; break;
7c39369e
VZ
103 case wxCURSOR_PAINT_BRUSH: gdk_cur = GDK_SPRAYCAN; break;
104 case wxCURSOR_MAGNIFIER: gdk_cur = GDK_PLUS; break;
105 case wxCURSOR_CHAR: gdk_cur = GDK_XTERM; break;
2d17d68f
RR
106 case wxCURSOR_LEFT_BUTTON: gdk_cur = GDK_LEFTBUTTON; break;
107 case wxCURSOR_MIDDLE_BUTTON: gdk_cur = GDK_MIDDLEBUTTON; break;
108 case wxCURSOR_RIGHT_BUTTON: gdk_cur = GDK_RIGHTBUTTON; break;
13971833
RD
109 case wxCURSOR_BULLSEYE: gdk_cur = GDK_TARGET; break;
110
957d856c
VZ
111 case wxCURSOR_POINT_LEFT: gdk_cur = GDK_SB_LEFT_ARROW; break;
112 case wxCURSOR_POINT_RIGHT: gdk_cur = GDK_SB_RIGHT_ARROW; break;
c801d85f 113/*
7c39369e
VZ
114 case wxCURSOR_DOUBLE_ARROW: gdk_cur = GDK_DOUBLE_ARROW; break;
115 case wxCURSOR_CROSS_REVERSE: gdk_cur = GDK_CROSS_REVERSE; break;
2d17d68f
RR
116 case wxCURSOR_BASED_ARROW_UP: gdk_cur = GDK_BASED_ARROW_UP; break;
117 case wxCURSOR_BASED_ARROW_DOWN: gdk_cur = GDK_BASED_ARROW_DOWN; break;
c801d85f 118*/
76471ff7 119
7c39369e 120 default:
223d09f6 121 wxFAIL_MSG(wxT("unsupported cursor type"));
7c39369e 122 // will use the standard one
7c39369e 123 break;
2d17d68f 124 }
8bbe427f 125
2d17d68f 126 M_CURSORDATA->m_cursor = gdk_cursor_new( gdk_cur );
ff7b1510 127}
c801d85f 128
c2fa61e8 129extern GtkWidget *wxGetRootWindow();
a1db952f
VS
130
131wxCursor::wxCursor(const char bits[], int width, int height,
132 int hotSpotX, int hotSpotY,
f516d986 133 const char maskBits[], const wxColour *fg, const wxColour *bg)
a1db952f
VS
134{
135 if (!maskBits)
136 maskBits = bits;
137 if (!fg)
138 fg = wxBLACK;
139 if (!bg)
140 bg = wxWHITE;
141 if (hotSpotX < 0 || hotSpotX >= width)
142 hotSpotX = 0;
143 if (hotSpotY < 0 || hotSpotY >= height)
144 hotSpotY = 0;
145
c2fa61e8
RD
146 GdkBitmap *data = gdk_bitmap_create_from_data( wxGetRootWindow()->window, (gchar *) bits, width, height );
147 GdkBitmap *mask = gdk_bitmap_create_from_data( wxGetRootWindow()->window, (gchar *) maskBits, width, height);
a1db952f
VS
148
149 m_refData = new wxCursorRefData;
150 M_CURSORDATA->m_cursor = gdk_cursor_new_from_pixmap(
151 data, mask, fg->GetColor(), bg->GetColor(),
152 hotSpotX, hotSpotY );
153
154 gdk_bitmap_unref( data );
155 gdk_bitmap_unref( mask );
156}
157
7eff657c 158#if wxUSE_IMAGE
0fc5dbf5 159
7eff657c
JS
160wxCursor::wxCursor( const wxImage & image )
161{
162 unsigned char * rgbBits = image.GetData();
0fc5dbf5
VZ
163 int w = image.GetWidth() ;
164 int h = image.GetHeight();
165 bool bHasMask = image.HasMask();
7eff657c
JS
166 int imagebitcount = (w*h)/8;
167
7eff657c
JS
168 unsigned char * bits = new unsigned char [imagebitcount];
169 unsigned char * maskBits = new unsigned char [imagebitcount];
170
0fc5dbf5 171 int i, j, i8; unsigned char c, cMask;
7eff657c 172 for (i=0; i<imagebitcount; i++)
0fc5dbf5 173 {
7eff657c
JS
174 bits[i] = 0;
175 i8 = i * 8;
176
177 cMask = 1;
178 for (j=0; j<8; j++)
0fc5dbf5
VZ
179 {
180 // possible overflow if we do the summation first ?
181 c = rgbBits[(i8+j)*3]/3 + rgbBits[(i8+j)*3+1]/3 + rgbBits[(i8+j)*3+2]/3;
182 //if average value is > mid grey
183 if (c>127)
184 bits[i] = bits[i] | cMask;
185 cMask = cMask * 2;
7eff657c 186 }
0fc5dbf5
VZ
187 }
188
189 unsigned long keyMaskColor;
7eff657c 190 if (bHasMask)
0fc5dbf5
VZ
191 {
192 unsigned char
193 r = image.GetMaskRed(),
194 g = image.GetMaskGreen(),
195 b = image.GetMaskBlue();
7eff657c
JS
196
197 for (i=0; i<imagebitcount; i++)
198 {
0fc5dbf5
VZ
199 maskBits[i] = 0x0;
200 i8 = i * 8;
7eff657c 201
0fc5dbf5
VZ
202 cMask = 1;
203 for (j=0; j<8; j++)
204 {
205 if (rgbBits[(i8+j)*3] != r || rgbBits[(i8+j)*3+1] != g || rgbBits[(i8+j)*3+2] != b)
206 maskBits[i] = maskBits[i] | cMask;
207 cMask = cMask * 2;
208 }
7eff657c 209 }
0fc5dbf5
VZ
210
211 keyMaskColor = (r << 16) | (g << 8) | b;
212 }
213 else // no mask
214 {
7eff657c 215 for (i=0; i<imagebitcount; i++)
0fc5dbf5
VZ
216 maskBits[i] = 0xFF;
217
218 // init it to avoid compiler warnings
219 keyMaskColor = 0;
220 }
221
fa1fcc66 222 // find the most frequent color(s)
952ae1e8 223 wxImageHistogram histogram;
fa1fcc66 224 image.ComputeHistogram(histogram);
7eff657c 225
0fc5dbf5 226 // colors as rrggbb
7eff657c 227 unsigned long key;
952ae1e8 228 unsigned long value;
7eff657c 229
fa1fcc66 230 long colMostFreq = 0;
952ae1e8 231 unsigned long nMost = 0;
fa1fcc66 232 long colNextMostFreq = 0;
952ae1e8 233 unsigned long nNext = 0;
fa1fcc66
VZ
234 for ( wxImageHistogram::iterator entry = histogram.begin();
235 entry != histogram.end();
236 ++entry )
7eff657c 237 {
952ae1e8
VS
238 value = entry->second.value;
239 key = entry->first;
240 if ( !bHasMask || (key != keyMaskColor) )
7eff657c 241 {
952ae1e8 242 if (value > nMost)
7eff657c 243 {
952ae1e8 244 nMost = value;
fa1fcc66 245 colMostFreq = key;
7eff657c 246 }
952ae1e8 247 else if (value > nNext)
7eff657c 248 {
952ae1e8 249 nNext = value;
fa1fcc66 250 colNextMostFreq = key;
7eff657c
JS
251 }
252 }
253 }
254
fa1fcc66
VZ
255 wxColour fg = wxColour ( (unsigned char)(colMostFreq >> 16),
256 (unsigned char)(colMostFreq >> 8),
257 (unsigned char)(colMostFreq) );
7eff657c 258
fa1fcc66
VZ
259 wxColour bg = wxColour ( (unsigned char)(colNextMostFreq >> 16),
260 (unsigned char)(colNextMostFreq >> 8),
261 (unsigned char)(colNextMostFreq) );
7eff657c 262
624d506b
CE
263 int fg_intensity = fg.Red() + fg.Green() + fg.Blue();
264 int bg_intensity = bg.Red() + bg.Green() + bg.Blue();
86e69fa5
MR
265
266 if (bg_intensity > fg_intensity)
267 {
624d506b
CE
268 //swap fg and bg
269 wxColour tmp = fg;
270 fg = bg;
271 bg = tmp;
86e69fa5 272 }
624d506b 273
fa1fcc66
VZ
274 int hotSpotX;
275 int hotSpotY;
7eff657c 276
671d2130
MB
277 if (image.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X))
278 hotSpotX = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X);
fa1fcc66
VZ
279 else
280 hotSpotX = 0;
281
671d2130
MB
282 if (image.HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y))
283 hotSpotY = image.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y);
fa1fcc66
VZ
284 else
285 hotSpotY = 0;
15dadf31 286
7eff657c 287 if (hotSpotX < 0 || hotSpotX >= w)
952ae1e8 288 hotSpotX = 0;
7eff657c 289 if (hotSpotY < 0 || hotSpotY >= h)
952ae1e8 290 hotSpotY = 0;
7eff657c 291
fa1fcc66
VZ
292 GdkBitmap *data = gdk_bitmap_create_from_data(wxGetRootWindow()->window,
293 (gchar *) bits, w, h);
294 GdkBitmap *mask = gdk_bitmap_create_from_data(wxGetRootWindow()->window,
295 (gchar *) maskBits, w, h);
7eff657c
JS
296
297 m_refData = new wxCursorRefData;
fa1fcc66
VZ
298 M_CURSORDATA->m_cursor = gdk_cursor_new_from_pixmap
299 (
300 data,
301 mask,
302 fg.GetColor(), bg.GetColor(),
303 hotSpotX, hotSpotY
304 );
7eff657c
JS
305
306 gdk_bitmap_unref( data );
307 gdk_bitmap_unref( mask );
0fc5dbf5 308 delete [] bits;
7eff657c 309 delete [] maskBits;
7eff657c 310}
0fc5dbf5
VZ
311
312#endif // wxUSE_IMAGE
7eff657c 313
8bbe427f 314wxCursor::~wxCursor()
c801d85f 315{
ff7b1510 316}
c801d85f 317
8f884a0d 318GdkCursor *wxCursor::GetCursor() const
c801d85f 319{
8f884a0d 320 return M_CURSORDATA->m_cursor;
ff7b1510 321}
c801d85f 322
8f884a0d 323wxGDIRefData *wxCursor::CreateGDIRefData() const
c801d85f 324{
8f884a0d
VZ
325 return new wxCursorRefData;
326}
327
328wxGDIRefData *wxCursor::CloneGDIRefData(const wxGDIRefData *data) const
329{
5c33522f 330 return new wxCursorRefData(*static_cast<const wxCursorRefData *>(data));
ff7b1510 331}
c801d85f
KB
332
333//-----------------------------------------------------------------------------
334// busy cursor routines
335//-----------------------------------------------------------------------------
336
238d735d 337extern wxCursor g_globalCursor;
7c39369e 338
238d735d 339static wxCursor gs_savedCursor;
89a43902 340static int gs_busyCount = 0;
c801d85f 341
f6bcfd97
BP
342const wxCursor &wxBusyCursor::GetStoredCursor()
343{
344 return gs_savedCursor;
345}
346
347const wxCursor wxBusyCursor::GetBusyCursor()
348{
349 return wxCursor(wxCURSOR_WATCH);
350}
351
8bbe427f 352void wxEndBusyCursor()
c801d85f 353{
238d735d 354 if (--gs_busyCount > 0)
89a43902
VZ
355 return;
356
238d735d
RR
357 wxSetCursor( gs_savedCursor );
358 gs_savedCursor = wxNullCursor;
13971833 359
d1dea842 360 if (wxTheApp)
8b532f8c 361 wxTheApp->ProcessIdle();
ff7b1510 362}
c801d85f 363
f516d986 364void wxBeginBusyCursor( const wxCursor *WXUNUSED(cursor) )
c801d85f 365{
238d735d 366 if (gs_busyCount++ > 0)
89a43902
VZ
367 return;
368
238d735d 369 wxASSERT_MSG( !gs_savedCursor.Ok(),
223d09f6 370 wxT("forgot to call wxEndBusyCursor, will leak memory") );
7c39369e 371
238d735d 372 gs_savedCursor = g_globalCursor;
13971833 373
238d735d 374 wxSetCursor( wxCursor(wxCURSOR_WATCH) );
13971833 375
d1dea842 376 if (wxTheApp)
3352cfff 377 wxTheApp->ProcessIdle();
15dadf31 378
7e410431 379 gdk_flush();
ff7b1510 380}
c801d85f 381
8bbe427f 382bool wxIsBusy()
c801d85f 383{
89a43902 384 return gs_busyCount > 0;
ff7b1510 385}
c801d85f
KB
386
387void wxSetCursor( const wxCursor& cursor )
388{
13971833 389 if (g_isIdle)
238d735d
RR
390 wxapp_install_idle_handler();
391
392 g_globalCursor = cursor;
ff7b1510 393}