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