1 /*
2 * This file is part of the XForms library package.
3 *
4 * XForms is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2.1, or
7 * (at your option) any later version.
8 *
9 * XForms is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with XForms. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18
19 /**
20 * \file cursor.c
21 *.
22 * This file is part of the XForms library package.
23 * Copyright (c) 1996-2002 T.C. Zhao
24 * All rights reserved.
25 *
26 * Cursor routines
27 *
28 * name is one of the standard symbolic cursor names (XC_watch etc) or
29 * the constants defined by XFORMS (FL_INVISIBLE_CURSOR etc)
30 *
31 * Cursor is the cursor usable in XDefineCursor(win, cursor)
32 */
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include "include/forms.h"
39 #include "flinternal.h"
40
41
42 #define MAX_CURSORS 64 /* max. number of bitmap cursors */
43 #define MAX_SEQ 24 /* max. number cursors per animation */
44
45
46 /* Cursor cache */
47
48 typedef struct {
49 int name;
50 int ncursor;
51 int cur_cursor;
52 Window win;
53 int timeout_id;
54 int timeout;
55 Cursor cur[ MAX_SEQ ];
56 } CurStruct;
57
58
59 /* Pre-built cursors */
60
61 static CurStruct prebuilt[ ] =
62 {
63 { XC_watch, 0, 0, None, 0, 0, { 0 } },
64 { XC_sb_right_arrow, 0, 0, None, 0, 0, { 0 } },
65 { XC_hand2, 0, 0, None, 0, 0, { 0 } },
66 { XC_top_left_arrow, 0, 0, None, 0, 0, { 0 } },
67 { XC_tcross, 0, 0, None, 0, 0, { 0 } },
68 { XC_pirate, 0, 0, None, 0, 0, { 0 } }
69 };
70
71 static CurStruct *cursors = NULL;
72
73 static int fl_default_curname = XC_top_left_arrow; /* xforms' default */
74
75 #ifndef XC_num_glyphs
76 #define XC_num_glyphs 255
77 #endif
78
79 static int user_cur_name = XC_num_glyphs;
80
81 static CurStruct *find_timeout( Window win );
82
83
84 /***************************************
85 ***************************************/
86
87 static CurStruct *
add_cursor(int name,Cursor cur)88 add_cursor( int name,
89 Cursor cur )
90 {
91 CurStruct *c = cursors;
92 static int warned;
93
94 while ( c->name && c->name != name )
95 c++;
96
97 if ( c < cursors + MAX_CURSORS )
98 {
99 c->name = name;
100 c->cur[ c->ncursor++ ] = cur;
101 }
102 else if ( ! warned )
103 {
104 M_err( "add_cursor", "too many cursors" );
105 warned = 1;
106 }
107 return c;
108 }
109
110
111 /***************************************
112 ***************************************/
113
114 static Cursor
create_bitmap_cursor(const char * source,const char * mask,int w,int h,int hotx,int hoty)115 create_bitmap_cursor( const char * source,
116 const char * mask,
117 int w,
118 int h,
119 int hotx,
120 int hoty )
121 {
122 Pixmap s,
123 m = None;
124 XColor fg,
125 bg;
126 Cursor cur;
127 Window win = fl_root;
128
129 s = XCreateBitmapFromData( flx->display, win, source, w, h );
130
131 if ( mask )
132 m = XCreateBitmapFromData( flx->display, win, mask, w, h );
133
134 fg.red = fg.green = fg.blue = 0;
135 bg.red = bg.green = bg.blue = 0xffff;
136 cur = XCreatePixmapCursor( flx->display, s, m, &fg, &bg, hotx, hoty );
137
138 return cur;
139 }
140
141
142 /***************************************
143 ***************************************/
144
145 static void
init_cursors(void)146 init_cursors( void )
147 {
148 static int ok;
149 CurStruct *c;
150 static char c_bits[ ] = { 0x00 };
151
152 if ( ok )
153 return;
154
155 ok = 1;
156
157 if ( ! cursors )
158 {
159 cursors = fl_calloc( MAX_CURSORS, sizeof *c );
160 memcpy( cursors, prebuilt, sizeof prebuilt );
161 }
162
163 for ( c = cursors; c->name; c++ )
164 c->cur[ c->ncursor++ ] = XCreateFontCursor( flx->display, c->name );
165
166 /* Create an invisible cursor */
167
168 add_cursor( FL_INVISIBLE_CURSOR,
169 create_bitmap_cursor( c_bits, c_bits, 1, 1, 0, 0 ) );
170
171 /* Add the default cursor */
172
173 add_cursor( FL_DEFAULT_CURSOR,
174 XCreateFontCursor( flx->display, fl_default_curname ) );
175 }
176
177
178 /***************************************
179 ***************************************/
180
181 void
fli_free_cursors(void)182 fli_free_cursors( void )
183 {
184 fli_safe_free( cursors );
185 }
186
187
188 /***************************************
189 ***************************************/
190
191 static void
animate_cursor(int id FL_UNUSED_ARG,void * data)192 animate_cursor( int id FL_UNUSED_ARG,
193 void * data )
194 {
195 CurStruct *cur = data;
196
197 cur->timeout_id = 0;
198 fl_set_cursor( cur->win, cur->name );
199 }
200
201
202 /***************************************
203 * Set cursor for win to name. Name is either the standard XC_ or
204 * Form defined
205 ***************************************/
206
207 void
fl_set_cursor(Window win,int name)208 fl_set_cursor( Window win,
209 int name )
210 {
211 CurStruct *c = cursors;
212
213 init_cursors( );
214
215 if ( win == 0 )
216 {
217 M_err( "fl_set_cursor", "Bad Window" );
218 return;
219 }
220
221 for ( ; c->name; c++ )
222 {
223 if ( c->name == name )
224 {
225 if ( c->ncursor > 1 )
226 {
227 int n = c->cur_cursor % c->ncursor;
228 XDefineCursor( flx->display, win, c->cur[ n ] );;
229 c->cur_cursor++;
230 c->win = win;
231 if ( c->timeout_id == 0 )
232 c->timeout_id =
233 fl_add_timeout( c->timeout, animate_cursor, c );
234 }
235 else
236 {
237 CurStruct *cur = find_timeout( win );
238
239 if ( cur && cur->timeout_id )
240 {
241 fl_remove_timeout( cur->timeout_id );
242 cur->timeout_id = 0;
243 }
244 XDefineCursor( flx->display, win, c->cur[ 0 ] );;
245 }
246 return;
247 }
248 }
249
250 XDefineCursor( flx->display, win, fli_get_cursor_byname( name ) );
251 }
252
253
254 /***************************************
255 * To be used in XDefineCursor
256 ***************************************/
257
258 Cursor
fli_get_cursor_byname(int name)259 fli_get_cursor_byname( int name )
260 {
261 CurStruct *c;
262 Cursor cur = 0;
263
264 init_cursors( );
265
266 for ( c = cursors; c->name; c++ )
267 {
268 if ( c->name == name )
269 {
270 int n = c->cur_cursor % c->ncursor;
271 c->cur_cursor++;
272 return c->cur[ n ];
273 }
274 }
275
276 /* Take a wild shot: since we can generate the default X cursor on the
277 fly we don't have to always save them to the cursor structure */
278
279 if ( name < XC_num_glyphs - 1 )
280 {
281 static int nn;
282 cur = XCreateFontCursor( flx->display, name );
283 if ( nn < 10 )
284 {
285 add_cursor( name, cur );
286 nn++;
287 }
288 }
289 else
290 {
291 M_err( "fli_get_cursor_byname", "Unknown cursor: %d\n", name );
292 cur = fli_get_cursor_byname( FL_DEFAULT_CURSOR ); /* recursion */
293 }
294
295 return cur;
296 }
297
298
299 /***************************************
300 ***************************************/
301
302 void
fl_set_cursor_color(int name,FL_COLOR fg,FL_COLOR bg)303 fl_set_cursor_color( int name,
304 FL_COLOR fg,
305 FL_COLOR bg )
306 {
307 XColor xfg,
308 xbg;
309 int r,
310 g,
311 b;
312 Cursor cur = fli_get_cursor_byname( name );
313
314 fl_getmcolor( fg, &r, &g, &b );
315 xfg.red = ( r << 8 ) | 0xff;
316 xfg.green = ( g << 8 ) | 0xff;
317 xfg.blue = ( b << 8 ) | 0xff;
318
319 fl_getmcolor( bg, &r, &g, &b );
320 xbg.red = ( r << 8 ) | 0xff;
321 xbg.green = ( g << 8 ) | 0xff;
322 xbg.blue = ( b << 8 ) | 0xff;
323
324 XRecolorCursor( flx->display, cur, &xfg, &xbg );
325 }
326
327
328 /***************************************
329 ***************************************/
330
331 int
fl_create_bitmap_cursor(const char * source,const char * mask,int w,int h,int hotx,int hoty)332 fl_create_bitmap_cursor( const char * source,
333 const char * mask,
334 int w,
335 int h,
336 int hotx,
337 int hoty )
338 {
339 Cursor cur;
340
341 init_cursors( );
342 cur = create_bitmap_cursor( source, mask, w, h, hotx, hoty );
343 add_cursor( user_cur_name, cur );
344
345 return user_cur_name++;
346 }
347
348
349 /***************************************
350 * cursor animation
351 ***************************************/
352
353 int
fl_create_animated_cursor(int * cur_names,int timeout)354 fl_create_animated_cursor( int * cur_names,
355 int timeout )
356 {
357 int *n = cur_names,
358 k = MAX_SEQ;
359 CurStruct *c = 0;
360
361 for ( ; *n >= 0 && --k >= 0; n++ )
362 c = add_cursor( user_cur_name, fli_get_cursor_byname( *n ) );
363
364 if ( c )
365 c->timeout = timeout > 0 ? timeout : 20;
366
367 return user_cur_name++;
368 }
369
370
371 /***************************************
372 ***************************************/
373
374 static CurStruct *
find_timeout(Window win)375 find_timeout( Window win )
376 {
377 CurStruct *c = cursors;
378
379 for ( ; c->name; c++ )
380 if ( c->win == win && c->timeout_id )
381 return c;
382
383 return 0;
384 }
385
386
387 /*
388 * Local variables:
389 * tab-width: 4
390 * indent-tabs-mode: nil
391 * End:
392 */
393