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 xdraw.c
21  *
22  *  This file is part of the XForms library package.
23  *  Copyright (c) 1996-2002  T.C. Zhao and Mark Overmars
24  *  All rights reserved.
25  *
26  *  Basic low level drawing routines in Xlib.
27  *
28  *  BUGS: All form window share a common GC and color map.
29  */
30 
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 
35 #include "include/forms.h"
36 #include "flinternal.h"
37 
38 
39 static int fli_mono_dither( unsigned long );
40 static void fli_set_current_gc( GC );
41 
42 static GC dithered_gc;
43 
44 
45 /*******************************************************************
46  * Rectangle routines
47  ****************************************************************{**/
48 
49 
50 /***************************************
51  * Function for drawing a (possibly filled) rectangle
52  ***************************************/
53 
54 void
fl_rectangle(int fill,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,FL_COLOR col)55 fl_rectangle( int      fill,
56               FL_Coord x,
57               FL_Coord y,
58               FL_Coord w,
59               FL_Coord h,
60               FL_COLOR col )
61 {
62     int bw = fli_dithered( fl_vmode ) && fli_mono_dither( col );
63     GC gc = flx->gc;
64     int ( * draw_as )( Display *,
65                        Drawable,
66                        GC,
67                        int,
68                        int,
69                        unsigned int,
70                        unsigned int );
71 
72     if ( flx->win == None || w <= 0 || h <= 0 )
73         return;
74 
75     fli_canonicalize_rect( &x, &y, &w, &h );
76 
77     draw_as = fill ? XFillRectangle : XDrawRectangle;
78 
79     if ( bw && fill )
80     {
81         fli_set_current_gc( fli_whitegc );
82         draw_as( flx->display, flx->win, flx->gc, x, y, w, h );
83         fli_set_current_gc( dithered_gc );
84     }
85 
86 
87     fl_color( bw ? FL_BLACK : col );
88     draw_as( flx->display, flx->win, flx->gc, x, y, w, h );
89 
90     if ( bw )
91         fli_set_current_gc( gc );
92 }
93 
94 
95 /****** End of rectangle routines ***********************}***/
96 
97 
98 /****************************************************************
99  * Polygon and polylines
100  ***********************************************************{****/
101 
102 
103 /***************************************
104  * Function for drawing a closed (possibly filled) polygon.
105  * The 'xp' argument must point to an array with n + 1 elements!
106  ***************************************/
107 
108 void
fl_polygon(int fill,FL_POINT * xp,int n,FL_COLOR col)109 fl_polygon( int        fill,
110             FL_POINT * xp,
111             int        n,
112             FL_COLOR   col )
113 {
114     int bw = fli_dithered( fl_vmode ) && fli_mono_dither( col );
115     GC gc = flx->gc;
116 
117     if ( flx->win == None || n <= 0 )
118         return;
119 
120     if ( bw )
121     {
122         flx->gc = dithered_gc;
123         fl_color( FL_WHITE );
124         if ( fill )
125             XFillPolygon( flx->display, flx->win, flx->gc, xp, n,
126                           Nonconvex, CoordModeOrigin );
127         else
128         {
129             xp[ n ].x = xp[ 0 ].x;
130             xp[ n ].y = xp[ 0 ].y;
131             XDrawLines( flx->display, flx->win, flx->gc, xp, n + 1,
132                         CoordModeOrigin );
133         }
134     }
135 
136     fl_color( bw ? FL_BLACK : col );
137 
138     if ( fill )
139         XFillPolygon( flx->display, flx->win, flx->gc, xp, n,
140                       Nonconvex, CoordModeOrigin );
141     else
142     {
143         xp[ n ].x = xp[ 0 ].x;
144         xp[ n ].y = xp[ 0 ].y;
145         XDrawLines( flx->display, flx->win, flx->gc, xp, n + 1,
146                     CoordModeOrigin );
147     }
148 
149     if ( bw )
150         flx->gc = gc;
151 }
152 
153 
154 /****************************************************************
155  * Draws a circle at (x, y) woth radius r and col as to color
156  * of the outline
157  **********************************************************{******/
158 
159 void
fl_circ(FL_COORD x,FL_COORD y,FL_COORD r,FL_COLOR col)160 fl_circ( FL_COORD x,
161          FL_COORD y,
162          FL_COORD r,
163          FL_COLOR col )
164 {
165     fl_oval( 0, x - r, y - r, 2 * r, 2 * r, col );
166 }
167 
168 
169 /****************************************************************
170  * Draws a filled circle at (x, y) woth radius r in color col
171  **********************************************************{******/
172 
173 void
fl_circf(FL_COORD x,FL_COORD y,FL_COORD r,FL_COLOR col)174 fl_circf( FL_COORD x,
175           FL_COORD y,
176           FL_COORD r,
177           FL_COLOR col )
178 {
179     fl_oval( 1, x - r, y - r, 2 * r, 2 * r, col );
180 }
181 
182 
183 /****************************************************************
184  * Draws a filled circle at (x, y) woth radius r in color col and
185  * the circumfence in black.
186  **********************************************************{******/
187 
188 void
fl_circbound(FL_COORD x,FL_COORD y,FL_COORD r,FL_COLOR col)189 fl_circbound( FL_COORD x,
190               FL_COORD y,
191               FL_COORD r,
192               FL_COLOR col )
193 {
194     fl_ovalbound( x - r, y - r, 2 * r, 2 * r, col );
195 }
196 
197 
198 /****************************************************************
199  * Function for drawing a (possibly filled) ellipse.
200  **********************************************************{******/
201 
202 void
fl_oval(int fill,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,FL_COLOR col)203 fl_oval( int      fill,
204          FL_Coord x,
205          FL_Coord y,
206          FL_Coord w,
207          FL_Coord h,
208          FL_COLOR col )
209 {
210     int bw = fli_dithered( fl_vmode ) && fli_mono_dither( col );
211     GC gc = flx->gc;
212     int ( * draw_as )( Display *,
213                        Drawable,
214                        GC,
215                        int,
216                        int,
217                        unsigned int,
218                        unsigned int,
219                        int,
220                        int );
221 
222     if ( flx->win == None || w <= 0 || h <= 0 )
223         return;
224 
225     draw_as = fill ? XFillArc : XDrawArc;
226 
227     if ( bw )
228     {
229         fli_set_current_gc( fli_whitegc );
230         draw_as( flx->display, flx->win, flx->gc, x, y, w, h, 0, 360 * 64 );
231         fli_set_current_gc( dithered_gc );
232     }
233 
234     fl_color( bw ? FL_BLACK : col );
235 
236     if ( w >= 0 && h >= 0 )
237         draw_as( flx->display, flx->win, flx->gc, x, y, w, h, 0, 360 * 64 );
238 
239     if ( bw )
240         fli_set_current_gc( gc );
241 }
242 
243 
244 /***************************************
245  * Draws a filled ellipse with a black border
246  ***************************************/
247 
248 void
fl_ovalbound(FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,FL_COLOR col)249 fl_ovalbound( FL_Coord x,
250               FL_Coord y,
251               FL_Coord w,
252               FL_Coord h,
253               FL_COLOR col )
254 {
255     if ( flx->win == None || w <= 0 || h <= 0 )
256         return;
257 
258     fl_color( col );
259     XFillArc( flx->display, flx->win, flx->gc, x, y, w, h, 0, 360 * 64 );
260     fl_color( FL_BLACK );
261     XDrawArc( flx->display, flx->win, flx->gc, x, y, w - 1, h - 1, 0,
262               360 * 64 );
263 }
264 
265 
266 /******* End of ellipse routines ****************}***********/
267 
268 /****************************************************************
269  *
270  * Arcs
271  ****************************************************************/
272 
273 /***************************************
274  ***************************************/
275 
276 void
fl_ovalarc(int fill,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,int t0,int dt,FL_COLOR col)277 fl_ovalarc( int      fill,
278             FL_Coord x,
279             FL_Coord y,
280             FL_Coord w,
281             FL_Coord h,
282             int      t0,
283             int      dt,
284             FL_COLOR col )
285 {
286     int mono = fli_dithered( fl_vmode ) && fli_mono_dither( col );
287     int ( * draw_as )( Display *,
288                        Drawable,
289                        GC,
290                        int,
291                        int,
292                        unsigned int,
293                        unsigned int,
294                        int,
295                        int );
296 
297     if ( flx->win == None || w <= 0 || h <= 0 )
298         return;
299 
300     draw_as = fill ? XFillArc : XDrawArc;
301 
302     if ( mono )
303     {
304         fli_set_current_gc( fli_whitegc );
305         draw_as( flx->display, flx->win, flx->gc, x, y, w, h,
306                  t0 * 6.4, dt * 6.4 );
307         fli_set_current_gc( dithered_gc );
308     }
309 
310     fl_color( mono ? FL_BLACK : col );
311 
312     if ( w >= 0 && h >= 0 )
313         draw_as( flx->display, flx->win, flx->gc, x, y, w, h,
314                  t0 * 6.4, dt * 6.4 );
315 
316     if ( mono )
317         fli_set_current_gc( fl_state[ fl_vmode ].gc[ 0 ] );
318 }
319 
320 
321 /***************************************
322  ***************************************/
323 
324 void
fl_arcf(FL_COORD x,FL_Coord y,FL_COORD r,int a1,int a2,FL_COLOR col)325 fl_arcf( FL_COORD x,
326          FL_Coord y,
327          FL_COORD r,
328          int      a1,
329          int      a2,
330          FL_COLOR col )
331 {
332     fl_pieslice( 1, x - r, y - r, 2 * r, 2 * r, a1, a2, col );
333 }
334 
335 
336 /***************************************
337  ***************************************/
338 
339 void
fl_arc(FL_COORD x,FL_Coord y,FL_COORD r,int a1,int a2,FL_COLOR col)340 fl_arc( FL_COORD x,
341         FL_Coord y,
342         FL_COORD r,
343         int      a1,
344         int      a2,
345         FL_COLOR col )
346 {
347     fl_pieslice( 0, x - r, y - r, 2 * r, 2 * r, a1, a2, col );
348 }
349 
350 
351 /***************************************
352  ***************************************/
353 
354 void
fl_pieslice(int fill,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,int a1,int a2,FL_COLOR col)355 fl_pieslice( int      fill,
356              FL_Coord x,
357              FL_Coord y,
358              FL_Coord w,
359              FL_Coord h,
360              int      a1,
361              int      a2,
362              FL_COLOR col )
363 {
364     int delta = a2 - a1,
365         bw = fli_dithered( fl_vmode ) && fli_mono_dither( col );
366     GC gc = flx->gc;
367     int ( * draw_as )( Display *,
368                        Drawable,
369                        GC,
370                        int,
371                        int,
372                        unsigned int,
373                        unsigned int,
374                        int,
375                        int );
376 
377     if ( flx->win == None || w <= 0 || h <= 0)
378         return;
379 
380     draw_as = fill ? XFillArc : XDrawArc;
381 
382     if ( bw )
383     {
384         fli_set_current_gc( fli_whitegc );
385         draw_as( flx->display, flx->win, flx->gc, x, y, w, h,
386                  a1 * 6.4, delta * 6.4 );
387         fli_set_current_gc( dithered_gc );
388     }
389 
390     fl_color( bw ? FL_BLACK : col );
391 
392     if ( w >= 0 && h >= 0 )
393         draw_as( flx->display, flx->win, flx->gc, x, y, w, h,
394                  a1 * 6.4, delta * 6.4 );
395     if ( bw )
396         fli_set_current_gc( gc );
397 }
398 
399 
400 /*********************************************************************
401  * Line segments
402  *****************************************************************{***/
403 
404 
405 /***************************************
406  ***************************************/
407 
408 void
fl_lines(FL_POINT * xp,int n,FL_COLOR col)409 fl_lines( FL_POINT * xp,
410           int        n,
411           FL_COLOR   col )
412 {
413     if ( flx->win == None  || n <= 0 )
414         return;
415 
416     fl_color( col );
417 
418     /* We may need to break up the request into smaller pieces */
419 
420     if ( fli_context->ext_request_size >= n )
421         XDrawLines( flx->display, flx->win, flx->gc, xp, n, CoordModeOrigin );
422     else
423     {
424         int req = fli_context->ext_request_size;
425         int i,
426             nchunks = ( n + ( n / req ) ) / req,
427             left;
428         FL_POINT *p = xp;
429 
430         for ( i = 0; i < nchunks; i++, p += req - 1 )
431             XDrawLines( flx->display, flx->win, flx->gc, p, req,
432                         CoordModeOrigin );
433 
434         left = xp + n - p;
435 
436         if ( left )
437         {
438             if ( left == 1 )
439             {
440                 p--;
441                 left++;
442             }
443 
444             XDrawLines( flx->display, flx->win, flx->gc, p, left,
445                         CoordModeOrigin );
446         }
447     }
448 }
449 
450 
451 /***************************************
452  * Drwas a simple line from (x1,y1) to (x2,y2)
453  ***************************************/
454 
455 void
fl_line(FL_Coord xi,FL_Coord yi,FL_Coord xf,FL_Coord yf,FL_COLOR c)456 fl_line( FL_Coord xi,
457          FL_Coord yi,
458          FL_Coord xf,
459          FL_Coord yf,
460          FL_COLOR c )
461 {
462     if ( flx->win == None )
463         return;
464 
465     fl_color( c );
466     XDrawLine( flx->display, flx->win, flx->gc, xi, yi, xf, yf );
467 }
468 
469 
470 /**************** End of line segments *******************}*********/
471 
472 
473 /* points */
474 
475 /***************************************
476  * Draws a simple point at the given position
477  ***************************************/
478 
479 void
fl_point(FL_Coord x,FL_Coord y,FL_COLOR c)480 fl_point( FL_Coord x,
481           FL_Coord y,
482           FL_COLOR c )
483 {
484     if ( flx->win == None )
485         return;
486 
487     fl_color( c );
488     XDrawPoint( flx->display, flx->win, flx->gc, x, y );
489 }
490 
491 
492 /***************************************
493  * Draws a set of simple point at the given positions
494  ***************************************/
495 
496 void
fl_points(FL_POINT * p,int np,FL_COLOR c)497 fl_points( FL_POINT * p,
498            int        np,
499            FL_COLOR   c )
500 {
501     if ( flx->win == None || np <= 0 )
502         return;
503 
504     fl_color( c );
505     XDrawPoints( flx->display, flx->win, flx->gc, p, np, CoordModeOrigin );
506 }
507 
508 
509 /********************************************************************
510  * Basic drawing attributes
511  ****************************************************************{*/
512 
513 static int lw     = 0,
514            ls     = LineSolid,
515            drmode = GXcopy;
516 
517 
518 /***************************************
519  ***************************************/
520 
521 void
fl_linewidth(int n)522 fl_linewidth( int n )
523 {
524     XGCValues gcvalue;
525     unsigned long gcmask;
526 
527     if ( lw == n )
528         return;
529 
530     gcmask = GCLineWidth;
531     gcvalue.line_width = lw = n;
532     XChangeGC( flx->display, flx->gc, gcmask, &gcvalue );
533 }
534 
535 
536 /***************************************
537  ***************************************/
538 
539 int
fl_get_linewidth(void)540 fl_get_linewidth( void )
541 {
542     return lw;
543 }
544 
545 
546 static void fli_xdashedlinestyle( Display *,
547                                   GC,
548                                   const char *,
549                                   int );
550 
551 /***************************************
552  ***************************************/
553 
554 void
fli_xlinestyle(Display * d,GC gc,int n)555 fli_xlinestyle( Display * d,
556                 GC       gc,
557                 int      n )
558 {
559     static char dots[ ]    = { 2, 4 };
560     static char dotdash[ ] = { 7, 3, 2, 3 };
561     static char ldash[ ]   = { 10, 4 };
562     XGCValues gcvalue;
563     unsigned long gcmask;
564 
565     if ( ls == n )
566         return;
567 
568     ls = n;
569 
570     gcmask = GCLineStyle;
571 
572     if ( n == FL_DOT )
573         fli_xdashedlinestyle( d, gc, dots, 2 );
574     else if ( n == FL_DOTDASH )
575         fli_xdashedlinestyle( d, gc, dotdash, 4 );
576     else if ( n == FL_LONGDASH )
577         fli_xdashedlinestyle( d, gc, ldash, 2 );
578     if ( n > LineDoubleDash )
579         n = LineOnOffDash;
580 
581     gcvalue.line_style = n;
582     XChangeGC( d, gc, gcmask, &gcvalue );
583 }
584 
585 
586 /***************************************
587  ***************************************/
588 
589 void
fl_linestyle(int n)590 fl_linestyle( int n )
591 {
592     fli_xlinestyle( flx->display, flx->gc, n );
593 }
594 
595 
596 /***************************************
597  ***************************************/
598 
599 int
fl_get_linestyle(void)600 fl_get_linestyle( void )
601 {
602     return ls;
603 }
604 
605 
606 /***************************************
607  ***************************************/
608 
609 int
fl_get_drawmode(void)610 fl_get_drawmode( void )
611 {
612     return drmode;
613 }
614 
615 
616 /***************************************
617  ***************************************/
618 
619 void
fl_drawmode(int request)620 fl_drawmode( int request )
621 {
622     if ( drmode != request )
623         XSetFunction( flx->display, flx->gc, drmode = request );
624 }
625 
626 
627 /***************************************
628  ***************************************/
629 
630 static void
fli_xdashedlinestyle(Display * d,GC gc,const char * dash,int ndash)631 fli_xdashedlinestyle( Display    * d,
632                       GC           gc,
633                       const char * dash,
634                       int          ndash )
635 {
636     static char default_dash[ ] = { 4, 4 };
637 
638     if ( dash == NULL )
639     {
640         dash = default_dash;
641         ndash = 2;
642     }
643 
644     XSetDashes( d, gc, 0, ( char * ) dash, ndash );
645 }
646 
647 
648 /***************************************
649  ***************************************/
650 
651 void
fl_dashedlinestyle(const char * dash,int ndash)652 fl_dashedlinestyle( const char * dash,
653                     int          ndash )
654 {
655     static char default_dash[ ] = { 4, 4 };
656 
657     /* Check that the input is reasonable - XSetDashes() requires that
658        there's at least one element in the 'dash' array and that none
659        of its elements are 0. If one of these conditions isn't satis-
660        fied (or 'dash' itself is NULL) set the defaut dash pattern. */
661 
662     if ( dash )
663     {
664         int i;
665 
666         for ( i = 0; i < ndash; i++ )
667             if ( dash[ i ] == '\0' )
668             {
669                 M_warn( "fl_dashedlinestyle", "Invalid '\0' in dash pattern "
670                         "array, using default pattern" );
671                 ndash = 0;
672                 break;
673             }
674     }
675 
676     if ( ! dash || ! ndash )
677     {
678         dash = default_dash;
679         ndash = 2;
680     }
681 
682     XSetDashes( flx->display, flx->gc, 0, ( char * ) dash, ndash );
683 }
684 
685 
686 /************************************************************************
687  * Clipping stuff
688  ***********************************************************************/
689 /*
690  *  Remember global clipping so unset_clipping will restore it. Most
691  *  useful as part of event dispatching
692  */
693 
694 enum {
695     FLI_GLOBAL_CLIP = 0,
696     FLI_NORMAL_CLIP = 1,
697     FLI_TEXT_CLIP   = 2,
698     FLI_GC_CLIP     = 3
699 };
700 
701 
702 static int fli_is_clipped[ ] = { 0, 0, 0, 0 };
703 static FL_RECT fli_clip_rect[ ] = { { 0, 0, 0, 0 },
704                                     { 0, 0, 0, 0 },
705                                     { 0, 0, 0, 0 },
706                                     { 0, 0, 0, 0 } };
707 
708 
709 #define SET_RECT( t, a, b, c, d )  \
710    do {                            \
711        ( t ).x      = a;           \
712        ( t ).y      = b;           \
713        ( t ).width  = c;           \
714        ( t ).height = d;           \
715    } while ( 0 )
716 
717 
718 #define GET_RECT( t, a, b, c, d )  \
719    do {                            \
720        *a = ( t ).x;               \
721        *b = ( t ).y;               \
722        *c = ( t ).width;           \
723        *d = ( t ).height;          \
724    } while ( 0 )
725 
726 
727 /***************************************
728  * Returns if global clipping is switched on - in which case
729  * the region for global clipping can be obtained via a call
730  * of fli_get_global_clipping( ).
731  ***************************************/
732 
733 int
fl_is_global_clipped(void)734 fl_is_global_clipped( void )
735 {
736     return fli_is_clipped[ FLI_GLOBAL_CLIP ];
737 }
738 
739 
740 /***************************************
741  * Helper function for determining if normal or text clipping is set
742  * (also reports if global clipping is set when 'include_global' is
743  * set).
744  ***************************************/
745 
746 static int
is_clipped(int type,int include_global)747 is_clipped( int type,
748             int include_global )
749 {
750     return    fli_is_clipped[ type ]
751            || ( include_global && fli_is_clipped[ FLI_GLOBAL_CLIP ] );
752 }
753 
754 
755 /***************************************
756  * Sets global clipping to the specified rectangle. If normal clipping
757  * is already on the rectange use is the one resulting from intersecting
758  * the requested rectangle with the one for normal clipping. Text is
759  * clipped in the same way. If called with a negative width or height
760  * global clipping is switched off.
761  ***************************************/
762 
763 void
fli_set_global_clipping(FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h)764 fli_set_global_clipping( FL_Coord x,
765                          FL_Coord y,
766                          FL_Coord w,
767                          FL_Coord h )
768 {
769     /* Calling the function with a rectangle with a negative width or height
770        results in switching off of global clipping */
771 
772     if ( w < 0 || h < 0 )
773     {
774         fli_unset_global_clipping( );
775         return;
776     }
777 
778     SET_RECT( fli_clip_rect[ FLI_GLOBAL_CLIP ], x, y, w, h );
779 
780     /* If normal clipping is already on intersect the new global and the
781        normal clip area and set clipping to the result. If normal clipping
782        is off just use the rectangle specified by the arguments. */
783 
784     if ( fli_is_clipped[ FLI_NORMAL_CLIP ] )
785     {
786         FL_RECT * r = fli_intersect_rects( fli_clip_rect + FLI_GLOBAL_CLIP,
787                                            fli_clip_rect + FLI_NORMAL_CLIP );
788 
789         if ( r )
790         {
791             XSetClipRectangles( flx->display, flx->gc, 0, 0, r, 1, Unsorted );
792             fli_safe_free( r );
793         }
794         else
795         {
796             FL_RECT n = { 0, 0, 0, 0 };
797 
798             XSetClipRectangles( flx->display, flx->gc, 0, 0, &n, 1, Unsorted );
799         }
800     }
801     else
802         XSetClipRectangles( flx->display, flx->gc, 0, 0,
803                             &fli_clip_rect[ FLI_GLOBAL_CLIP ], 1, Unsorted );
804 
805     /* The same again for text clipping */
806 
807     if ( fli_is_clipped[ FLI_TEXT_CLIP ] )
808     {
809         FL_RECT * r = fli_intersect_rects( fli_clip_rect + FLI_GLOBAL_CLIP,
810                                            fli_clip_rect + FLI_TEXT_CLIP );
811 
812         if ( r )
813         {
814             XSetClipRectangles( flx->display, flx->textgc, 0, 0, r, 1,
815                                 Unsorted );
816             fli_safe_free( r );
817         }
818         else
819         {
820             FL_RECT n = { 0, 0, 0, 0 };
821 
822             XSetClipRectangles( flx->display, flx->textgc, 0, 0, &n, 1,
823                                 Unsorted );
824         }
825     }
826     else
827         XSetClipRectangles( flx->display, flx->textgc, 0, 0,
828                             fli_clip_rect + FLI_GLOBAL_CLIP, 1, Unsorted );
829 
830     fli_is_clipped[ FLI_GLOBAL_CLIP ] = 1;
831 }
832 
833 
834 /***************************************
835  * Unsets global clipping - "normal" and text clipping, if set, are retained
836  ***************************************/
837 
838 void
fli_unset_global_clipping(void)839 fli_unset_global_clipping( void )
840 {
841     if ( ! fli_is_clipped[ FLI_GLOBAL_CLIP ] )
842         return;
843 
844     SET_RECT( fli_clip_rect[ FLI_GLOBAL_CLIP ], 0, 0, 0, 0 );
845 
846     /* If normal clipping is also on set the clipping rectangle to that set
847        for normal clipping, otherwise switch clipping off completely. */
848 
849     if ( fli_is_clipped[ FLI_NORMAL_CLIP ] )
850         XSetClipRectangles( flx->display, flx->gc, 0, 0,
851                             fli_clip_rect + FLI_NORMAL_CLIP, 1, Unsorted );
852     else
853         XSetClipMask( flx->display, flx->gc, None );
854 
855     /* Same for text clipping */
856 
857     if ( fli_is_clipped[ FLI_TEXT_CLIP ] )
858         XSetClipRectangles( flx->display, flx->textgc, 0, 0,
859                             fli_clip_rect + FLI_TEXT_CLIP, 1, Unsorted );
860     else
861         XSetClipMask( flx->display, flx->textgc, None );
862 
863     fli_is_clipped[ FLI_GLOBAL_CLIP ] = 0;
864 }
865 
866 
867 /***************************************
868  * Returns a pointer to the rectangle used for global clipping (only
869  * to be used when global clipping is on!)
870  ***************************************/
871 
872 FL_RECT *
fli_get_global_clip_rect(void)873 fli_get_global_clip_rect( void )
874 {
875     return fli_clip_rect + FLI_GLOBAL_CLIP;
876 }
877 
878 
879 /***************************************
880  * Function returns as its return value if global clipping is on or off
881  * and, via the pointer arguments, the clipping rectangle.
882  ***************************************/
883 
884 int
fl_get_global_clipping(FL_Coord * x,FL_Coord * y,FL_Coord * w,FL_Coord * h)885 fl_get_global_clipping( FL_Coord * x,
886                         FL_Coord * y,
887                         FL_Coord * w,
888                         FL_Coord * h )
889 {
890     GET_RECT( fli_clip_rect[ FLI_GLOBAL_CLIP ], x, y, w, h );
891     return fli_is_clipped[ FLI_GLOBAL_CLIP ];
892 }
893 
894 
895 /***************************************
896  * Helper function to switch off normal, text or GC clipping - if global
897  * clipping is on it will be retained.
898  ***************************************/
899 
900 static void
unset_clipping(int type,GC gc)901 unset_clipping( int type,
902                 GC  gc )
903 {
904     if ( ! fli_is_clipped[ type ] )
905         return;
906 
907     SET_RECT( fli_clip_rect[ type ], 0, 0, 0, 0 );
908 
909     if ( fli_is_clipped[ FLI_GLOBAL_CLIP ] )
910         XSetClipRectangles( flx->display, gc, 0, 0,
911                             fli_clip_rect + FLI_GLOBAL_CLIP, 1, Unsorted );
912     else
913         XSetClipMask( flx->display, gc, None );
914 
915     fli_is_clipped[ type ] = 0;
916 }
917 
918 
919 /***************************************
920  * Helper function to switch normal, text or GC clipping on for a certain
921  * a certain region. 'type' is the type of clipping and 'gc' the GC for
922  * which the clipping is to be set. If global clipping is already on the
923  * clipping region is the intersection of the requested clipping region
924  * with the clipping region for global clipping.
925  ***************************************/
926 
927 static void
set_clipping(int type,GC gc,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h)928 set_clipping( int      type,
929               GC       gc,
930               FL_Coord x,
931               FL_Coord y,
932               FL_Coord w,
933               FL_Coord h )
934 {
935     if ( w < 0 || h < 0 )
936     {
937         unset_clipping( type, gc );
938         return;
939     }
940 
941     SET_RECT( fli_clip_rect[ type ], x, y, w, h );
942 
943     if ( fli_is_clipped[ FLI_GLOBAL_CLIP ] )
944     {
945         FL_RECT * r = fli_intersect_rects( fli_clip_rect + FLI_GLOBAL_CLIP,
946                                            fli_clip_rect + type );
947 
948         if ( r )
949         {
950             XSetClipRectangles( flx->display, gc, 0, 0, r, 1, Unsorted );
951             fli_safe_free( r );
952         }
953         else
954         {
955             FL_RECT n = { 0, 0, 0, 0 };
956 
957             XSetClipRectangles( flx->display, gc, 0, 0, &n, 1, Unsorted );
958         }
959     }
960     else
961         XSetClipRectangles( flx->display, gc, 0, 0, &fli_clip_rect[ type ],
962                             1, Unsorted );
963 
964     fli_is_clipped[ type ] = 1;
965 }
966 
967 
968 /***************************************
969  * Helper function for determining if normal or text clipping is on and the
970  * region clipped to. 'type' is the type of clipping. If 'include_global' is
971  * set also clipping due to global clipping is taken into account (and the
972  * reported clipping region is the one resulting from intersection of the
973  * clipping region for the requested type of clipping and the one for global
974  * clipping). The function returns as its return value if there's clipping
975  * going on (which may, when 'include_global', also be due to global clipping).
976  ***************************************/
977 
978 static int
get_clipping(int type,int include_global,FL_Coord * x,FL_Coord * y,FL_Coord * w,FL_Coord * h)979 get_clipping( int        type,
980               int        include_global,
981               FL_Coord * x,
982               FL_Coord * y,
983               FL_Coord * w,
984               FL_Coord * h )
985 {
986     if (    ! ( include_global && fli_is_clipped[ FLI_GLOBAL_CLIP ] )
987          && fli_is_clipped[ type ] )
988         GET_RECT( fli_clip_rect[ type ], x, y, w, h );
989     else if ( include_global && fli_is_clipped[ FLI_GLOBAL_CLIP ] )
990     {
991         if ( fli_is_clipped[ type ] )
992         {
993             FL_RECT * r =
994                 fli_intersect_rects( fli_clip_rect + FLI_GLOBAL_CLIP,
995                                      fli_clip_rect + type );
996 
997             if ( r )
998             {
999                 GET_RECT( *r, x, y, w, h );
1000                 fl_free( r );
1001             }
1002         }
1003         else
1004             GET_RECT( fli_clip_rect[ FLI_GLOBAL_CLIP ], x, y, w, h );
1005     }
1006 
1007     return is_clipped( type, include_global );
1008 }
1009 
1010 
1011 /***************************************
1012  * Returns if "normal" (i.e. non-text) clipping is switched on.
1013  * If 'include_global' is set also also global clipping (used
1014  * e.g. when redrawing on an expose event) is on, otherwise only
1015  * clipping set via a call of fl_set_clipping() is reported.
1016  ***************************************/
1017 
1018 int
fl_is_clipped(int include_global)1019 fl_is_clipped( int include_global )
1020 {
1021     return is_clipped( FLI_NORMAL_CLIP, include_global );
1022 }
1023 
1024 
1025 /***************************************
1026  * Function for setting normal clipping. If global clipping is on the
1027  * rectangle set for clipping is the intersection of the rectangle specified
1028  * by the arguments and the one for global clipping.  Specifying a negative
1029  * clipping width or height results in clipping becoming switched off.
1030  ***************************************/
1031 
1032 void
fl_set_clipping(FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h)1033 fl_set_clipping( FL_Coord x,
1034                  FL_Coord y,
1035                  FL_Coord w,
1036                  FL_Coord h )
1037 {
1038     set_clipping( FLI_NORMAL_CLIP, flx->gc, x, y, w, h );
1039 }
1040 
1041 
1042 /****************************************
1043  * Function for switching of normal clipping. Note that global clipping
1044  * will be retained.
1045  ***************************************/
1046 
1047 void
fl_unset_clipping(void)1048 fl_unset_clipping( void )
1049 {
1050     unset_clipping( FLI_NORMAL_CLIP, flx->gc );
1051 }
1052 
1053 
1054 /***************************************
1055  * Function for determining if normal clipping is on and the region clipped
1056  * to. If 'include_global' is set also clipping due to global clipping is
1057  * taken into account (and the reported clipping region is the one resulting
1058  * from intersection of the normal clipping region and the one for global
1059  * clipping). The function returns as its return value if there's clipping
1060  * going on (which may, when 'include_global', also be due to global clipping).
1061  ***************************************/
1062 
1063 int
fl_get_clipping(int include_global,FL_Coord * x,FL_Coord * y,FL_Coord * w,FL_Coord * h)1064 fl_get_clipping( int        include_global,
1065                  FL_Coord * x,
1066                  FL_Coord * y,
1067                  FL_Coord * w,
1068                  FL_Coord * h )
1069 {
1070     return get_clipping( FLI_NORMAL_CLIP, include_global, x, y, w, h );
1071 }
1072 
1073 
1074 /***************************************
1075  * Returns if "text" clipping is switched on. If 'include_global'
1076  * is set also also global clipping (used e.g. when redrawing on
1077  * an expose event) is on, otherwise only clipping set via a call
1078  * of fl_set_text_clipping() is reported.
1079  ***************************************/
1080 
1081 int
fl_is_text_clipped(int include_global)1082 fl_is_text_clipped( int include_global )
1083 {
1084     return is_clipped( FLI_TEXT_CLIP, include_global );
1085 }
1086 
1087 
1088 /***************************************
1089  * Function for setting text clipping. If global clipping is on the rectangle
1090  * set for clipping is the intersection of the rectangle specified by the
1091  * arguments and the one for global clipping. Specifying a negative clipping
1092  * width or height results in clipping becoming switched off.
1093  ***************************************/
1094 
1095 void
fl_set_text_clipping(FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h)1096 fl_set_text_clipping( FL_Coord x,
1097                       FL_Coord y,
1098                       FL_Coord w,
1099                       FL_Coord h )
1100 {
1101     set_clipping( FLI_TEXT_CLIP, flx->textgc, x, y, w, h );
1102 }
1103 
1104 
1105 /***************************************
1106  * Function for switching of text clipping. Note that global clipping
1107  * will be retained.
1108  ***************************************/
1109 
1110 void
fl_unset_text_clipping(void)1111 fl_unset_text_clipping( void )
1112 {
1113     unset_clipping( FLI_TEXT_CLIP, flx->textgc );
1114 }
1115 
1116 
1117 /***************************************
1118  * Function for determining if text clipping is on and the region clipped
1119  * to. If 'include_global' is set also clipping due to global clipping is
1120  * taken into account (and the reported clipping region is the one resulting
1121  * from intersection of the text clipping region and the one for global
1122  * clipping). The function returns as its return value if there's clipping
1123  * going on (which may, when 'include_global', also be due to global clipping).
1124  ***************************************/
1125 
1126 int
fl_get_text_clipping(int include_global,FL_Coord * x,FL_Coord * y,FL_Coord * w,FL_Coord * h)1127 fl_get_text_clipping( int        include_global,
1128                       FL_Coord * x,
1129                       FL_Coord * y,
1130                       FL_Coord * w,
1131                       FL_Coord * h )
1132 {
1133     return get_clipping( FLI_TEXT_CLIP, include_global, x, y, w, h );
1134 }
1135 
1136 
1137 /***************************************
1138  * Function for setting clipping for the specified GC. If global clipping is
1139  * on the rectangle set for clipping is the intersection of the rectangle
1140  * specified by the arguments and the one for global clipping. Specifying a
1141  * negative clipping width or height results in clipping becoming switched off.
1142  ***************************************/
1143 
1144 void
fl_set_gc_clipping(GC gc,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h)1145 fl_set_gc_clipping( GC       gc,
1146                     FL_Coord x,
1147                     FL_Coord y,
1148                     FL_Coord w,
1149                     FL_Coord h )
1150 {
1151     fli_is_clipped[ FLI_GC_CLIP ] = 1;
1152     set_clipping( FLI_GC_CLIP, gc, x, y, w, h );
1153 }
1154 
1155 
1156 /***************************************
1157  * Function for switching of clipping for the given gc. Note that global
1158  * clipping will be retained.
1159  ***************************************/
1160 
1161 void
fl_unset_gc_clipping(GC gc)1162 fl_unset_gc_clipping( GC gc )
1163 {
1164     fli_is_clipped[ FLI_GC_CLIP ] = 1;
1165     unset_clipping( FLI_GC_CLIP, gc );
1166 }
1167 
1168 
1169 /***************************************
1170  * Function that allows to set additional (always reducing the clipping
1171  * rectangle further) to already set clipping - the intersection of the
1172  * region and the already set clipping region is calculated and clipping
1173  * then set to the resulting rectangle.
1174  ***************************************/
1175 
1176 void
fli_set_additional_clipping(FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h)1177 fli_set_additional_clipping( FL_Coord x,
1178                              FL_Coord y,
1179                              FL_Coord w,
1180                              FL_Coord h )
1181 {
1182     FL_RECT rect;
1183 
1184     SET_RECT( rect, x, y, w, h );
1185 
1186     if ( fli_is_clipped[ FLI_NORMAL_CLIP ] )
1187     {
1188         FL_RECT * r = fli_intersect_rects( fli_clip_rect + FLI_NORMAL_CLIP,
1189                                            &rect );
1190 
1191         if ( r )
1192         {
1193             rect = *r;
1194             fli_safe_free( r );
1195         }
1196         else
1197             SET_RECT( rect, 0, 0, 0, 0 );
1198     }
1199 
1200     fl_set_clipping( rect.x, rect.y, rect.width, rect.height );
1201 }
1202 
1203 
1204 /***************************************
1205  ***************************************/
1206 
1207 static void
fli_set_current_gc(GC gc)1208 fli_set_current_gc( GC gc )
1209 {
1210     if ( flx->gc == gc )
1211         return;
1212 
1213     flx->gc    = gc;
1214     flx->color = FL_NoColor;
1215 
1216     if (    fli_is_clipped[ FLI_GLOBAL_CLIP ]
1217          && fli_is_clipped[ FLI_NORMAL_CLIP ] )
1218     {
1219         FL_RECT * r = fli_intersect_rects( fli_clip_rect + FLI_GLOBAL_CLIP,
1220                                            fli_clip_rect + FLI_NORMAL_CLIP );
1221 
1222         if ( r )
1223         {
1224             XSetClipRectangles( flx->display, gc, 0, 0, r, 1, Unsorted );
1225             fli_safe_free( r );
1226         }
1227         else
1228         {
1229             FL_RECT n = { 0, 0, 0, 0 };
1230 
1231             XSetClipRectangles( flx->display, gc, 0, 0, &n, 1, Unsorted );
1232         }
1233     }
1234     else if ( fli_is_clipped[ FLI_GLOBAL_CLIP ] )
1235         XSetClipRectangles( flx->display, gc, 0, 0,
1236                             fli_clip_rect + FLI_GLOBAL_CLIP, 1, Unsorted );
1237     else if ( fli_is_clipped[ FLI_NORMAL_CLIP ] )
1238         XSetClipRectangles( flx->display, gc, 0, 0,
1239                             fli_clip_rect + FLI_NORMAL_CLIP, 1, Unsorted );
1240     else
1241         XSetClipMask( flx->display, gc, None );
1242 }
1243 
1244 
1245 /***************************************
1246  * Manually dither non-gray scale colors by changing default GC. Grayscales
1247  * are typically used in buttons, boxes etc, better not to dither them
1248  ***************************************/
1249 
1250 static int
fli_mono_dither(unsigned long col)1251 fli_mono_dither( unsigned long col )
1252 {
1253     int bwtrick = 0;
1254 
1255     switch ( col )
1256     {
1257         case FL_RED:
1258         case FL_MAGENTA:
1259         case FL_SLATEBLUE:
1260         case FL_PALEGREEN:
1261         case FL_DARKGOLD:
1262         case FL_INACTIVE_COL:
1263             dithered_gc = fli_bwgc[ 1 ];
1264             bwtrick     = 1;
1265             break;
1266 
1267         case FL_YELLOW:
1268         case FL_CYAN:
1269         case FL_INDIANRED:
1270         case FL_GREEN:
1271             dithered_gc = fli_bwgc[ 2 ];
1272             bwtrick     = 1;
1273             break;
1274 
1275         case FL_BLUE:
1276             dithered_gc = fli_bwgc[ 0 ];
1277             bwtrick     = 1;
1278             break;
1279 
1280         default:
1281             if ( col >= FL_FREE_COL1 )
1282             {
1283                 int r,
1284                     g,
1285                     b;
1286 
1287                 fl_get_icm_color( col, &r, &g, &b );
1288                 if ( ( bwtrick = ( r > 70 && r <= 210 ) ) )
1289                     dithered_gc = fli_bwgc[ r / 70 - 1 ];
1290             }
1291             break;
1292     }
1293 
1294     return bwtrick;
1295 }
1296 
1297 
1298 /*
1299  * Local variables:
1300  * tab-width: 4
1301  * indent-tabs-mode: nil
1302  * End:
1303  */
1304