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