1 /* grX11su3.c -
2 *
3 * *********************************************************************
4 * * Copyright (C) 1985, 1990 Regents of the University of California. *
5 * * Permission to use, copy, modify, and distribute this *
6 * * software and its documentation for any purpose and without *
7 * * fee is hereby granted, provided that the above copyright *
8 * * notice appear in all copies. The University of California *
9 * * makes no representations about the suitability of this *
10 * * software for any purpose. It is provided "as is" without *
11 * * express or implied warranty. Export of this software outside *
12 * * of the United States of America may require an export license. *
13 * *********************************************************************
14 *
15 * This file contains additional functions to manipulate an X window system
16 * color display. Included here are device-dependent routines to draw and
17 * erase text and draw a grid.
18 *
19 */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <math.h>
24 #include <X11/Xlib.h>
25
26 #include "utils/magic.h"
27 #include "utils/geometry.h"
28 #include "graphics/graphics.h"
29 #include "windows/windows.h"
30 #include "graphics/graphicsInt.h"
31 #include "textio/textio.h"
32 #include "utils/signals.h"
33 #include "utils/utils.h"
34 #include "utils/hash.h"
35 #include "dbwind/dbwind.h"
36 #include "database/fonts.h"
37 #include "grX11Int.h"
38
39 /* locals */
40
41 static XFontStruct *grXFonts[4];
42 #define grSmallFont grXFonts[0]
43 #define grMediumFont grXFonts[1]
44 #define grLargeFont grXFonts[2]
45 #define grXLargeFont grXFonts[3]
46
47
48
49 /*---------------------------------------------------------
50 * grxDrawGrid:
51 * grxDrawGrid adds a grid to the grid layer, using the current
52 * write mask and color.
53 *
54 * Results:
55 * TRUE is returned normally. However, if the grid gets too small
56 * to be useful, then nothing is drawn and FALSE is returned.
57 *
58 * Side Effects: None.
59 *---------------------------------------------------------
60 */
61
62 #define GR_NUM_GRIDS 64
63
64 bool
grx11DrawGrid(prect,outline,clip)65 grx11DrawGrid (prect, outline, clip)
66 Rect *prect; /* A rectangle that forms the template
67 * for the grid. Note: in order to maintain
68 * precision for the grid, the rectangle
69 * coordinates are specified in units of
70 * screen coordinates multiplied by SUBPIXEL.
71 */
72 int outline; /* the outline style */
73 Rect *clip; /* a clipping rectangle */
74 {
75 int xsize, ysize;
76 int x, y;
77 int xstart, ystart;
78 XSegment seg[GR_NUM_GRIDS];
79 int snum, low, hi, shifted;
80
81 xsize = prect->r_xtop - prect->r_xbot;
82 ysize = prect->r_ytop - prect->r_ybot;
83 if (!xsize || !ysize || GRID_TOO_SMALL(xsize, ysize))
84 return FALSE;
85
86 xstart = prect->r_xbot % xsize;
87 while (xstart < clip->r_xbot << SUBPIXELBITS) xstart += xsize;
88 ystart = prect->r_ybot % ysize;
89 while (ystart < clip->r_ybot << SUBPIXELBITS) ystart += ysize;
90
91 grx11SetLineStyle(outline);
92
93 snum = 0;
94 low = grMagicToX(clip->r_ybot);
95 hi = grMagicToX(clip->r_ytop);
96 for (x = xstart; x < (clip->r_xtop + 1) << SUBPIXELBITS; x += xsize)
97 {
98 if (snum == GR_NUM_GRIDS)
99 {
100 XDrawSegments(grXdpy, grCurrent.window, grGCDraw, seg, snum);
101 snum = 0;
102 }
103 shifted = x >> SUBPIXELBITS;
104 seg[snum].x1 = shifted;
105 seg[snum].y1 = low;
106 seg[snum].x2 = shifted;
107 seg[snum].y2 = hi;
108 snum++;
109 }
110 XDrawSegments(grXdpy, grCurrent.window, grGCDraw, seg, snum);
111
112 snum = 0;
113 low = clip->r_xbot;
114 hi = clip->r_xtop;
115 for (y = ystart; y < (clip->r_ytop + 1) << SUBPIXELBITS; y += ysize)
116 {
117 if (snum == GR_NUM_GRIDS)
118 {
119 XDrawSegments(grXdpy, grCurrent.window, grGCDraw, seg, snum);
120 snum = 0;
121 }
122 shifted = grMagicToX(y >> SUBPIXELBITS);
123 seg[snum].x1 = low;
124 seg[snum].y1 = shifted;
125 seg[snum].x2 = hi;
126 seg[snum].y2 = shifted;
127 snum++;
128 }
129 XDrawSegments(grXdpy, grCurrent.window, grGCDraw, seg, snum);
130 return TRUE;
131 }
132
133
134 /*---------------------------------------------------------
135 * grxLoadFont
136 * This local routine loads the X fonts used by Magic.
137 *
138 * Results: Success/failure
139 *
140 * Side Effects: None.
141 *---------------------------------------------------------
142 */
143
144 bool
grx11LoadFont()145 grx11LoadFont()
146 {
147 static char *fontnames[4] = {
148 X_FONT_SMALL,
149 X_FONT_MEDIUM,
150 X_FONT_LARGE,
151 X_FONT_XLARGE };
152 static char *optionnames[4] = {
153 "small",
154 "medium",
155 "large",
156 "xlarge"};
157
158 int i;
159 char *unable = "Unable to load font";
160
161 for (i=0; i!= 4; i++)
162 {
163 char *s = XGetDefault(grXdpy,"magic",optionnames[i]);
164 if (s) fontnames[i] = s;
165 if ((grXFonts[i] = XLoadQueryFont(grXdpy, fontnames[i])) == NULL)
166 {
167 TxError("%s %s\n",unable,fontnames[i]);
168 if ((grXFonts[i]= XLoadQueryFont(grXdpy,GR_DEFAULT_FONT))==NULL)
169 {
170 TxError("%s %s\n",unable,GR_DEFAULT_FONT);
171 return FALSE;
172 }
173 }
174 }
175 return TRUE;
176 }
177
178
179 /*---------------------------------------------------------
180 * grxSetCharSize:
181 * This local routine sets the character size in the display,
182 * if necessary.
183 *
184 * Results: None.
185 *
186 * Side Effects: None.
187 *---------------------------------------------------------
188 */
189
190 void
grx11SetCharSize(size)191 grx11SetCharSize (size)
192 int size; /* Width of characters, in pixels (6 or 8). */
193 {
194 grCurrent.fontSize = size;
195 switch (size)
196 {
197 case GR_TEXT_DEFAULT:
198 case GR_TEXT_SMALL:
199 grCurrent.font = grSmallFont;
200 break;
201 case GR_TEXT_MEDIUM:
202 grCurrent.font = grMediumFont;
203 break;
204 case GR_TEXT_LARGE:
205 grCurrent.font = grLargeFont;
206 break;
207 case GR_TEXT_XLARGE:
208 grCurrent.font = grXLargeFont;
209 break;
210 default:
211 TxError("%s%d\n", "grx11SetCharSize: Unknown character size ",
212 size );
213 break;
214 }
215 }
216
217
218 /*
219 * ----------------------------------------------------------------------------
220 * GrXTextSize --
221 *
222 * Determine the size of a text string.
223 *
224 * Results:
225 * None.
226 *
227 * Side effects:
228 * A rectangle is filled in that is the size of the text in pixels.
229 * The origin (0, 0) of this rectangle is located on the baseline
230 * at the far left side of the string.
231 * ----------------------------------------------------------------------------
232 */
233
234 void
GrX11TextSize(text,size,r)235 GrX11TextSize(text, size, r)
236 char *text;
237 int size;
238 Rect *r;
239 {
240 XCharStruct overall;
241 XFontStruct *font;
242 int dir,fa,fd;
243
244 switch (size) {
245 case GR_TEXT_DEFAULT:
246 case GR_TEXT_SMALL:
247 font = grSmallFont;
248 break;
249 case GR_TEXT_MEDIUM:
250 font = grMediumFont;
251 break;
252 case GR_TEXT_LARGE:
253 font = grLargeFont;
254 break;
255 case GR_TEXT_XLARGE:
256 font = grXLargeFont;
257 break;
258 default:
259 TxError("%s%d\n", "GrX11TextSize: Unknown character size ",
260 size );
261 break;
262 }
263 if (font == NULL) return;
264 XTextExtents(font, text, strlen(text), &dir, &fa, &fd, &overall);
265 r->r_ytop = overall.ascent;
266 r->r_ybot = -overall.descent;
267 r->r_xtop = overall.width - overall.lbearing;
268 r->r_xbot = -overall.lbearing - 1;
269 }
270
271
272 /*
273 * ----------------------------------------------------------------------------
274 * GrXReadPixel --
275 *
276 * Read one pixel from the screen.
277 *
278 * Results:
279 * An integer containing the pixel's color.
280 *
281 * Side effects:
282 * none.
283 *
284 * ----------------------------------------------------------------------------
285 */
286
287 int
GrX11ReadPixel(w,x,y)288 GrX11ReadPixel (w, x, y)
289 MagWindow *w;
290 int x,y; /* the location of a pixel in screen coords */
291 {
292 XImage *image;
293 unsigned long value;
294 XWindowAttributes att;
295
296 XGetWindowAttributes(grXdpy,grCurrent.window, &att);
297 if ( x < 0 || x >= att.width || grMagicToX(y) < 0
298 || grMagicToX(y) >= att.height)
299 return(0);
300 image = XGetImage(grXdpy, grCurrent.window, x, grMagicToX(y), 1, 1,
301 ~0, ZPixmap);
302 value = XGetPixel(image, 0, 0);
303 return (value & (1 << grDisplay.depth) - 1);
304 }
305
306
307 /*
308 * ----------------------------------------------------------------------------
309 * GrXBitBlt --
310 *
311 * Copy information in bit block transfers.
312 *
313 * Results:
314 * None.
315 *
316 * Side effects:
317 * changes the screen.
318 * ----------------------------------------------------------------------------
319 */
320
321 void
GrX11BitBlt(r,p)322 GrX11BitBlt(r, p)
323 Rect *r;
324 Point *p;
325 {
326 Drawable wind = (Drawable)grCurrent.window;
327
328 XCopyArea(grXdpy, wind, wind, grGCCopy,
329 r->r_xbot, grMagicToX(r->r_ytop),
330 r->r_xtop - r->r_xbot + 1, r->r_ytop - r->r_ybot + 1,
331 p->p_x, grMagicToX(p->p_y));
332 }
333
334 static GC grXcopyGC = (GC)NULL;
335
336 /*
337 * ----------------------------------------------------------------------------
338 * grx11FreeBackingStore --
339 * Free up Pixmap memory for a backing store cell.
340 *
341 * Results:
342 * None.
343 *
344 * Side effects:
345 * memory Free'd
346 * ----------------------------------------------------------------------------
347 */
348
349 void
grx11FreeBackingStore(MagWindow * window)350 grx11FreeBackingStore(MagWindow *window)
351 {
352 Pixmap pmap = (Pixmap)window->w_backingStore;
353 if (pmap == (Pixmap)NULL) return;
354 XFreePixmap(grXdpy, pmap);
355 window->w_backingStore = (ClientData)NULL;
356 /* XFreeGC(grXdpy, grXcopyGC); */
357 /* TxPrintf("grx11FreeBackingStore called\n"); */
358 }
359
360 /*
361 * ----------------------------------------------------------------------------
362 * grx11CreateBackingStore --
363 * Create Pixmap memory for a backing store cell and copy data
364 * from the window into it.
365 *
366 * Results:
367 * None.
368 *
369 * Side effects:
370 * memory Allocated.
371 *
372 * ----------------------------------------------------------------------------
373 */
374
375 void
grx11CreateBackingStore(MagWindow * w)376 grx11CreateBackingStore(MagWindow *w)
377 {
378 Pixmap pmap;
379 Window wind = (Window)w->w_grdata;
380 unsigned int width, height;
381 GC gc;
382 XGCValues gcValues;
383 int grDepth;
384
385 /* ignore for all windows except layout */
386 if (w->w_client != DBWclientID) return;
387
388 /* deferred */
389 if (w->w_grdata == (Window)NULL) return;
390
391 width = w->w_screenArea.r_xtop - w->w_screenArea.r_xbot;
392 height = w->w_screenArea.r_ytop - w->w_screenArea.r_ybot;
393
394 if (w->w_backingStore != (ClientData)NULL) grx11FreeBackingStore(w);
395
396 if (grXcopyGC == (GC)NULL)
397 {
398 gcValues.graphics_exposures = FALSE;
399 grXcopyGC = XCreateGC(grXdpy, wind, GCGraphicsExposures, &gcValues);
400 }
401
402 grDepth = grDisplay.depth;
403 if(grClass == 3) grDepth = 8; /* Needed since grDisplay.depth is reset
404 to 7 if Pseudocolor */
405
406 pmap = XCreatePixmap(grXdpy, wind, width, height, grDepth);
407 w->w_backingStore = (ClientData)pmap;
408
409 /* TxPrintf("grx11CreateBackingStore area %d %d %d %d\n",
410 w->w_screenArea.r_xbot, w->w_screenArea.r_ybot,
411 w->w_screenArea.r_xtop, w->w_screenArea.r_ytop); */
412 }
413
414 /*
415 * ----------------------------------------------------------------------------
416 * grx11GetBackingStore --
417 * Copy data from a backing store Pixmap into the indicated window.
418 *
419 * Results:
420 * TRUE if backing store was copied successfully, FALSE if not.
421 *
422 * Side effects:
423 * Data copied into Pixmap memory.
424 *
425 * ----------------------------------------------------------------------------
426 */
427
428 bool
grx11GetBackingStore(MagWindow * w,Rect * area)429 grx11GetBackingStore(MagWindow *w, Rect *area)
430 {
431 Pixmap pmap;
432 Window wind = (Window)w->w_grdata;
433 unsigned int width, height;
434 int ybot;
435 int xoff, yoff;
436 Rect r;
437
438 pmap = (Pixmap)w->w_backingStore;
439 if (pmap == (Pixmap)NULL)
440 return FALSE;
441
442 /* Make a local copy of area so we don't disturb the original */
443 r = *area;
444 GeoClip(&r, &(w->w_screenArea));
445
446 width = r.r_xtop - r.r_xbot;
447 height = r.r_ytop - r.r_ybot;
448 ybot = grMagicToX(r.r_ytop);
449
450 xoff = w->w_screenArea.r_xbot - w->w_allArea.r_xbot;
451 yoff = w->w_allArea.r_ytop - w->w_screenArea.r_ytop;
452
453 XCopyArea(grXdpy, pmap, wind, grXcopyGC, r.r_xbot - xoff, ybot - yoff,
454 width, height, r.r_xbot, ybot);
455
456 /* TxPrintf("grx11GetBackingStore %d %d %d %d\n",
457 r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop); */
458 return TRUE;
459 }
460
461 /*
462 * ----------------------------------------------------------------------------
463 * grx11ScrollBackingStore --
464 * Enable fast scrolling by shifting part of the backing store
465 * from one position to another, with the amount of shift indicated
466 * by the X and/or Y value of the indicated point.
467 *
468 * Results:
469 * TRUE on success, FALSE on failure.
470 *
471 * Side effects:
472 * Data shifted in Pixmap memory.
473 *
474 * ----------------------------------------------------------------------------
475 */
476
477 bool
grx11ScrollBackingStore(MagWindow * w,Point * shift)478 grx11ScrollBackingStore(MagWindow *w, Point *shift)
479 {
480 Pixmap pmap;
481 unsigned int width, height;
482 int xorigin, yorigin, xshift, yshift;
483
484 pmap = (Pixmap)w->w_backingStore;
485 if (pmap == (Pixmap)NULL)
486 {
487 TxPrintf("grx11ScrollBackingStore %d %d failure\n",
488 shift->p_x, shift->p_y);
489 return FALSE;
490 }
491
492 width = w->w_screenArea.r_xtop - w->w_screenArea.r_xbot;
493 height = w->w_screenArea.r_ytop - w->w_screenArea.r_ybot;
494 xorigin = 0;
495 yorigin = 0;
496 xshift = shift->p_x;
497 yshift = -shift->p_y;
498
499 if (xshift > 0)
500 width -= xshift;
501 else if (xshift < 0)
502 {
503 width += xshift;
504 xorigin = -xshift;
505 xshift = 0;
506 }
507 if (yshift > 0)
508 height -= yshift;
509 else if (yshift < 0)
510 {
511 height += yshift;
512 yorigin = -yshift;
513 yshift = 0;
514 }
515
516 XCopyArea(grXdpy, pmap, pmap, grXcopyGC, xorigin, yorigin, width, height,
517 xshift, yshift);
518
519 /* TxPrintf("grx11ScrollBackingStore %d %d\n", shift->p_x, shift->p_y); */
520 return TRUE;
521 }
522
523 /*
524 * ----------------------------------------------------------------------------
525 * grx11PutBackingStore --
526 * Copy data from the window into backing store.
527 *
528 * Results:
529 * None.
530 *
531 * Side effects:
532 * Graphics drawing into the window.
533 * ----------------------------------------------------------------------------
534 */
535
536 void
grx11PutBackingStore(MagWindow * w,Rect * area)537 grx11PutBackingStore(MagWindow *w, Rect *area)
538 {
539 Pixmap pmap = (Pixmap)w->w_backingStore;
540 Window wind = (Window)w->w_grdata;
541 unsigned int width, height;
542 int ybot, xoff, yoff;
543
544 if (pmap == (Pixmap)NULL) return;
545
546 /* Attempting to write backing store into an obscured */
547 /* window immediately invalidates everything in backing */
548 /* store. This is extreme, but is much simpler and under */
549 /* normal conditions faster than tracking all obscured */
550 /* areas separately. */
551
552 if (w->w_flags & WIND_OBSCURED)
553 {
554 grx11FreeBackingStore(w);
555 w->w_backingStore = (ClientData)NULL;
556 return;
557 }
558
559 width = area->r_xtop - area->r_xbot;
560 height = area->r_ytop - area->r_ybot;
561 ybot = grMagicToX(area->r_ytop);
562
563 xoff = w->w_screenArea.r_xbot - w->w_allArea.r_xbot;
564 yoff = w->w_allArea.r_ytop - w->w_screenArea.r_ytop;
565
566 XCopyArea(grXdpy, wind, pmap, grXcopyGC, area->r_xbot, ybot,
567 width, height, area->r_xbot - xoff, ybot - yoff);
568
569 /* TxPrintf("grx11PutBackingStore %d %d %d %d\n",
570 area->r_xbot, area->r_ybot, area->r_xtop, area->r_ytop); */
571 }
572
573 /*
574 * ----------------------------------------------------------------------------
575 * GrX11RectConvert --
576 * Convert a magic rectangle into an X11 rectangle
577 * (Both passed as pointers)
578 *
579 * Results:
580 * None.
581 *
582 * Side effects:
583 * Converted value returned in xr.
584 * ----------------------------------------------------------------------------
585 */
586
587 void
grx11RectConvert(mr,xr)588 grx11RectConvert(mr, xr)
589 Rect *mr;
590 XRectangle *xr;
591 {
592 xr->x = mr->r_xbot;
593 xr->y = grMagicToX(mr->r_ytop);
594 xr->width = mr->r_xtop - mr->r_xbot + 1;
595 xr->height = mr->r_ytop - mr->r_ybot + 1;
596 }
597
598 /*
599 *---------------------------------------------------------
600 * grx11FontText:
601 *
602 * This routine is a fancier version of grx11PutText used for
603 * drawing vector outline fonts from the fontList records.
604 *
605 *---------------------------------------------------------
606 */
607
608 void
grx11FontText(text,font,size,rotate,pos,clip,obscure)609 grx11FontText(text, font, size, rotate, pos, clip, obscure)
610 char *text;
611 int font;
612 int size; /* pixel size of the text */
613 int rotate; /* text rotation */
614 Point *pos; /* text base position */
615 Rect *clip;
616 LinkedRect *obscure;
617 {
618 char *tptr;
619 FontChar *ccur, *clist;
620 Point *coffset, *tp, loffset, locoffset, corners[4], lpos;
621 Rect *cbbox, charbbox, *frect;
622 int np, i, j, w, h, llx, lly, baseline;
623 XPoint *xp;
624 Pixmap pxm;
625 double fscale, scx, scy, tmpx, tmpy, rrad, cr, sr;
626 static GC fontgc = (GC)NULL;
627
628 frect = &DBFontList[font]->mf_extents;
629 fscale = (double)size / (double)frect->r_ytop;
630 rrad = (double)rotate * 0.0174532925;
631 cr = cos(rrad);
632 sr = sin(rrad);
633 lpos = GeoOrigin;
634
635 /* 1st pass: find the descent of the string */
636
637 baseline = 0;
638 for (tptr = text; *tptr != '\0'; tptr++)
639 {
640 DBFontChar(font, *tptr, NULL, NULL, &cbbox);
641 if (cbbox->r_ybot < -baseline)
642 baseline = -cbbox->r_ybot;
643 }
644 baseline = (int)((double)baseline * fscale);
645
646 for (tptr = text; *tptr != '\0'; tptr++)
647 {
648 scx = (double)lpos.p_x * fscale;
649 scy = (double)lpos.p_y * fscale;
650
651 tmpx = scx * cr + scy * sr;
652 tmpy = scy * cr - scx * sr;
653
654 loffset.p_x = pos->p_x + (int)round(tmpx);
655 loffset.p_y = grMagicToX(pos->p_y + baseline) + (int)round(tmpy);
656
657 DBFontChar(font, *tptr, &clist, &coffset, &cbbox);
658 np = 0;
659 for (ccur = clist; ccur != NULL; ccur = ccur->fc_next)
660 np += ccur->fc_numpoints;
661
662 xp = (XPoint *)mallocMagic(np * sizeof(XPoint));
663
664 j = 0;
665 for (ccur = clist; ccur != NULL; ccur = ccur->fc_next)
666 {
667 tp = ccur->fc_points;
668 for (i = 0; i < ccur->fc_numpoints; i++, j++)
669 {
670 scx = (double)tp[i].p_x * fscale;
671 scy = (double)tp[i].p_y * fscale;
672
673 tmpx = scx * cr - scy * sr;
674 tmpy = scx * sr + scy * cr;
675
676 xp[j].x = (int)round(tmpx);
677 xp[j].y = (int)round(tmpy);
678
679 /* Initialize bounding box */
680 if (j == 0)
681 {
682 charbbox.r_xbot = charbbox.r_xtop = xp[j].x;
683 charbbox.r_ybot = charbbox.r_ytop = xp[j].y;
684 }
685 else
686 {
687 if (xp[j].x < charbbox.r_xbot)
688 charbbox.r_xbot = xp[j].x;
689 else if (xp[j].x > charbbox.r_xtop)
690 charbbox.r_xtop = xp[j].x;
691 if (xp[j].y < charbbox.r_ybot)
692 charbbox.r_ybot = xp[j].y;
693 else if (xp[j].y > charbbox.r_ytop)
694 charbbox.r_ytop = xp[j].y;
695 }
696 }
697 }
698
699 /* Create a bitmap */
700
701 w = charbbox.r_xtop - charbbox.r_xbot + 1;
702 h = charbbox.r_ytop - charbbox.r_ybot + 1;
703
704 /* Adjust all points to the bounding box origin, and invert Y */
705 for (j = 0; j < np; j++)
706 {
707 xp[j].x -= charbbox.r_xbot;
708 xp[j].y = charbbox.r_ytop - xp[j].y;
709 }
710
711 pxm = XCreatePixmap(grXdpy, grCurrent.window, w, h, 1);
712
713 if (fontgc == (GC)NULL)
714 {
715 XGCValues values;
716 values.foreground = 0;
717 values.background = 0;
718 fontgc = XCreateGC(grXdpy, pxm, GCForeground | GCBackground, &values);
719 }
720
721 locoffset.p_x = loffset.p_x + charbbox.r_xbot;
722 locoffset.p_y = loffset.p_y - charbbox.r_ytop;
723
724 XSetForeground(grXdpy, fontgc, 0);
725 XSetFunction(grXdpy, fontgc, GXcopy);
726 XFillRectangle(grXdpy, pxm, fontgc, 0, 0, w, h);
727 XSetFunction(grXdpy, fontgc, GXxor);
728 XSetForeground(grXdpy, fontgc, 1);
729
730 j = 0;
731 for (ccur = clist; ccur != NULL; ccur = ccur->fc_next)
732 {
733 np = ccur->fc_numpoints;
734 XFillPolygon(grXdpy, pxm, fontgc, &xp[j], np, Complex, CoordModeOrigin);
735 j += np;
736 }
737 freeMagic((char *)xp);
738
739 XSetClipMask(grXdpy, grGCText, pxm);
740 XSetClipOrigin(grXdpy, grGCText, locoffset.p_x, locoffset.p_y);
741 XFillRectangle(grXdpy, grCurrent.window, grGCText, locoffset.p_x,
742 locoffset.p_y, w, h);
743
744 lpos.p_x += coffset->p_x;
745 lpos.p_y += coffset->p_y;
746
747 XFreePixmap(grXdpy, pxm);
748 }
749 }
750
751 /*---------------------------------------------------------
752 * grxPutText:
753 * (modified on SunPutText)
754 *
755 * This routine puts a chunk of text on the screen in the current
756 * color, size, etc. The caller must ensure that it fits on
757 * the screen -- no clipping is done except to the obscuring rectangle
758 * list and the clip rectangle.
759 *
760 * Results:
761 * none.
762 *
763 * Side Effects:
764 * The text is drawn on the screen.
765 *
766 *---------------------------------------------------------
767 */
768
769 void
grx11PutText(text,pos,clip,obscure)770 grx11PutText (text, pos, clip, obscure)
771 char *text; /* The text to be drawn. */
772 Point *pos; /* A point located at the leftmost point of
773 * the baseline for this string.
774 */
775 Rect *clip; /* A rectangle to clip against */
776 LinkedRect *obscure; /* A list of obscuring rectangles */
777
778 {
779 Rect location;
780 Rect overlap;
781 Rect textrect;
782 LinkedRect *ob;
783 void grX11suGeoSub();
784
785 if (grCurrent.font == NULL) return;
786
787 GrX11TextSize(text, grCurrent.fontSize, &textrect);
788
789 location.r_xbot = pos->p_x + textrect.r_xbot;
790 location.r_xtop = pos->p_x + textrect.r_xtop;
791 location.r_ybot = pos->p_y + textrect.r_ybot;
792 location.r_ytop = pos->p_y + textrect.r_ytop;
793
794 /* erase parts of the bitmap that are obscured */
795 for (ob = obscure; ob != NULL; ob = ob->r_next)
796 {
797 if (GEO_TOUCH(&ob->r_r, &location))
798 {
799 overlap = location;
800 GeoClip(&overlap, &ob->r_r);
801 grX11suGeoSub(&location, &overlap);
802 }
803 }
804
805 overlap = location;
806 GeoClip(&overlap, clip);
807
808 /* copy the text to the color screen */
809 if ((overlap.r_xbot < overlap.r_xtop)&&(overlap.r_ybot <= overlap.r_ytop))
810 {
811 XRectangle xr;
812
813 XSetFont(grXdpy, grGCText, grCurrent.font->fid);
814 grx11RectConvert(&overlap, &xr);
815 XSetClipRectangles(grXdpy, grGCText, 0, 0, &xr, 1, Unsorted);
816 XDrawString(grXdpy, grCurrent.window, grGCText,
817 pos->p_x, grMagicToX(pos->p_y),
818 text, strlen(text));
819 }
820 }
821
822
823 /*
824 *---------------------------------------------------------
825 * grX11suGeoSub --
826 * return the tallest sub-rectangle of r not obscured by area
827 * area must be within r.
828 *
829 * Results:
830 * None.
831 *
832 * Side effects:
833 * Source rectangle "r" is modified.
834 *---------------------------------------------------------
835 */
836
837 void
grX11suGeoSub(r,area)838 grX11suGeoSub(r, area)
839 Rect *r; /* Rectangle to be subtracted from. */
840 Rect *area; /* Area to be subtracted. */
841 {
842 if (r->r_xbot == area->r_xbot) r->r_xbot = area->r_xtop;
843 else
844 if (r->r_xtop == area->r_xtop) r->r_xtop = area->r_xbot;
845 else
846 if (r->r_ybot <= area->r_ybot) r->r_ybot = area->r_ytop;
847 else
848 if (r->r_ytop == area->r_ytop) r->r_ytop = area->r_ybot;
849 else
850 r->r_xtop = area->r_xbot;
851 }
852