upload tizen2.0 source
[framework/uifw/xorg/lib/libxaw.git] / src / AsciiSink.c
1 /***********************************************************
2
3 Copyright 1987, 1988, 1994, 1998  The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24
25
26 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
27
28                         All Rights Reserved
29
30 Permission to use, copy, modify, and distribute this software and its
31 documentation for any purpose and without fee is hereby granted,
32 provided that the above copyright notice appear in all copies and that
33 both that copyright notice and this permission notice appear in
34 supporting documentation, and that the name of Digital not be
35 used in advertising or publicity pertaining to distribution of the
36 software without specific, written prior permission.
37
38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44 SOFTWARE.
45
46 ******************************************************************/
47
48 #ifdef HAVE_CONFIG_H
49 #include <config.h>
50 #endif
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <X11/IntrinsicP.h>
54 #include <X11/StringDefs.h>
55 #include <X11/Xatom.h>
56 #include <X11/Xaw/XawInit.h>
57 #include <X11/Xaw/AsciiSinkP.h>
58 #include <X11/Xaw/AsciiSrcP.h>
59 #include <X11/Xaw/TextP.h>
60 #include "Private.h"
61
62 #ifdef GETLASTPOS
63 #undef GETLASTPOS               /* We will use our own GETLASTPOS */
64 #endif
65
66 #define GETLASTPOS      \
67         XawTextSourceScan(source, 0, XawstAll, XawsdRight, 1, True)
68
69 /*
70  * Class Methods
71  */
72 static void XawAsciiSinkClassPartInitialize(WidgetClass);
73 static void XawAsciiSinkInitialize(Widget, Widget, ArgList, Cardinal*);
74 static void XawAsciiSinkDestroy(Widget);
75 static void XawAsciiSinkResize(Widget);
76 static Boolean XawAsciiSinkSetValues(Widget, Widget, Widget,
77                                      ArgList, Cardinal*);
78 static int MaxLines(Widget, unsigned int);
79 static int MaxHeight(Widget, int);
80 static void SetTabs(Widget, int, short*);
81 static void DisplayText(Widget, int, int,
82                         XawTextPosition, XawTextPosition, Bool);
83 static void InsertCursor(Widget, int, int, XawTextInsertState);
84 static void FindPosition(Widget, XawTextPosition, int, int, Bool,
85                          XawTextPosition*, int*, int*);
86 static void FindDistance(Widget, XawTextPosition, int, XawTextPosition, int*,
87                          XawTextPosition*, int*);
88 static void Resolve(Widget, XawTextPosition, int, int, XawTextPosition*);
89 static void GetCursorBounds(Widget, XRectangle*);
90 #ifndef OLDXAW
91 static void AsciiPreparePaint(Widget, int, int,
92                               XawTextPosition, XawTextPosition, Bool);
93 static void AsciiDoPaint(Widget);
94 #endif
95
96 /*
97  * Prototypes
98  */
99 static void GetGC(AsciiSinkObject);
100 static int CharWidth(AsciiSinkObject, XFontStruct*, int, unsigned int);
101 static unsigned int PaintText(Widget w, GC gc, int x, int y,
102                               char *buf, int len, Bool);
103
104 /*
105  * Defined in TextSink.c
106  */
107 void _XawTextSinkClearToBackground(Widget, int, int, unsigned, unsigned);
108
109 /*
110  * Initialization
111  */
112 #define offset(field) XtOffsetOf(AsciiSinkRec, ascii_sink.field)
113 static XtResource resources[] = {
114   {
115     XtNfont,
116     XtCFont,
117     XtRFontStruct,
118     sizeof(XFontStruct*),
119     offset(font),
120     XtRString,
121     XtDefaultFont
122   },
123   {
124     XtNecho,
125     XtCOutput,
126     XtRBoolean,
127     sizeof(Boolean),
128     offset(echo),
129     XtRImmediate,
130     (XtPointer)True
131   },
132   {
133     XtNdisplayNonprinting,
134     XtCOutput,
135     XtRBoolean,
136     sizeof(Boolean),
137     offset(display_nonprinting),
138     XtRImmediate,
139     (XtPointer)
140     True
141   },
142 };
143 #undef offset
144
145 #define Superclass      (&textSinkClassRec)
146 AsciiSinkClassRec asciiSinkClassRec = {
147   /* object */
148   {
149     (WidgetClass)Superclass,    /* superclass */
150     "AsciiSink",                /* class_name */
151     sizeof(AsciiSinkRec),       /* widget_size */
152     XawInitializeWidgetSet,     /* class_initialize */
153     XawAsciiSinkClassPartInitialize,    /* class_part_initialize */
154     False,                      /* class_inited */
155     XawAsciiSinkInitialize,     /* initialize */
156     NULL,                       /* initialize_hook */
157     NULL,                       /* obj1 */
158     NULL,                       /* obj2 */
159     0,                          /* obj3 */
160     resources,                  /* resources */
161     XtNumber(resources),        /* num_resources */
162     NULLQUARK,                  /* xrm_class */
163     False,                      /* obj4 */
164     False,                      /* obj5 */
165     False,                      /* obj6 */
166     False,                      /* obj7 */
167     XawAsciiSinkDestroy,        /* destroy */
168     (XtProc)XawAsciiSinkResize, /* obj8 */
169     NULL,                       /* obj9 */
170     XawAsciiSinkSetValues,      /* set_values */
171     NULL,                       /* set_values_hook */
172     NULL,                       /* obj10 */
173     NULL,                       /* get_values_hook */
174     NULL,                       /* obj11 */
175     XtVersion,                  /* version */
176     NULL,                       /* callback_private */
177     NULL,                       /* obj12 */
178     NULL,                       /* obj13 */
179     NULL,                       /* obj14 */
180     NULL,                       /* extension */
181   },
182   /* text_sink */
183   {
184     DisplayText,                /* DisplayText */
185     InsertCursor,               /* InsertCursor */
186     XtInheritClearToBackground, /* ClearToBackground */
187     FindPosition,               /* FindPosition */
188     FindDistance,               /* FindDistance */
189     Resolve,                    /* Resolve */
190     MaxLines,                   /* MaxLines */
191     MaxHeight,                  /* MaxHeight */
192     SetTabs,                    /* SetTabs */
193     GetCursorBounds,            /* GetCursorBounds */
194 #ifndef OLDXAW
195     NULL                        /* extension */
196 #endif
197   },
198   /* ascii_sink */
199   {
200     NULL,                       /* extension */
201   }
202 };
203
204 WidgetClass asciiSinkObjectClass = (WidgetClass)&asciiSinkClassRec;
205
206 /*
207  * Implementation
208  */
209 static void
210 XawAsciiSinkClassPartInitialize(WidgetClass wc)
211 {
212 #ifndef OLDXAW
213     AsciiSinkObjectClass cclass = (AsciiSinkObjectClass)wc;
214     XrmQuark record_type = XrmPermStringToQuark("TextSink");
215     TextSinkExt ext = cclass->text_sink_class.extension;
216
217     while (ext) {
218         if (ext->record_type == record_type &&
219             ext->version == 1) {
220             ext->PreparePaint = AsciiPreparePaint;
221             ext->DoPaint = AsciiDoPaint;
222             break;
223         }
224         ext = (TextSinkExt)ext->next_extension;
225     }
226     if (ext == NULL)
227         XtError("TextSinkClass: cannot resolve extension.\n");
228 #endif
229 }
230
231 static int
232 CharWidth(AsciiSinkObject sink, XFontStruct *font, int x, unsigned int c)
233 {
234     int width = 0;
235
236     if (c == XawLF)
237         return (0);
238
239     if (c == XawTAB) {
240         int i;
241         Position *tab;
242
243         width = x;
244         /* Adjust for Left Margin */
245         x -= ((TextWidget)XtParent((Widget)sink))->text.left_margin;
246
247         i = 0;
248         tab = sink->text_sink.tabs;
249         /*CONSTCOND*/
250         while (1) {
251             if (x >= 0 && x < *tab)
252                 return (*tab - x);
253             /* Start again */
254             if (++i >= sink->text_sink.tab_count) {
255                 x -= *tab;
256                 i = 0;
257                 tab = sink->text_sink.tabs;
258                 if (width == x)
259                     return (0);
260             }
261             else
262                 ++tab;
263         }
264         /*NOTREACHED*/
265     }
266
267     if ((c & 0177) < XawSP || c == 0177) {
268         if (sink->ascii_sink.display_nonprinting) {
269             if (c > 0177) {
270                 width = CharWidth(sink, font, x, '\\');
271                 width += CharWidth(sink, font, x, ((c >> 6) & 7) + '0');
272                 width += CharWidth(sink, font, x, ((c >> 3) & 7) + '0');
273                 c = (c & 7) + '0';
274             }
275             else {
276                 width = CharWidth(sink, font, x, '^');
277                 if ((c |= 0100) == 0177)
278                     c = '?';
279             }
280         }
281         else
282             c = XawSP;
283     }
284
285     if (font->per_char
286         && (c >= font->min_char_or_byte2 && c <= font->max_char_or_byte2))
287         width += font->per_char[c - font->min_char_or_byte2].width;
288     else
289         width += font->min_bounds.width;
290
291     return (width);
292 }
293
294 #ifndef OLDXAW
295 static int
296 GetTextWidth(TextWidget ctx, int current_width, XFontStruct *font,
297              XawTextPosition from, int length)
298 {
299     int i, width = 0;
300     XawTextBlock block;
301     XawTextPosition pos = from;
302
303     while (length > 0) {
304         pos = XawTextSourceRead(ctx->text.source, from, &block, length);
305         length -= pos - from;
306         from = pos;
307         for (i = 0; i < block.length; i++)
308             width += CharWidth((AsciiSinkObject)ctx->text.sink, font,
309                                current_width + width,
310                                (unsigned char)block.ptr[i]);
311     }
312
313     return (width);
314 }
315
316 static
317 void CalculateBearing(TextWidget ctx, XawTextPosition position, int x, int y,
318                       int ascent, int descent, Bool highlight, Bool right)
319 {
320 /*
321  * Sample case:
322  *
323  * lbearing|    width    |rbearing
324  *         |             |
325  *         |           ####
326  *         |         ### |
327  *         |       ####  |
328  *         |      ####   |
329  *         |  ########## |
330  *         |    ####     |
331  *         |   ####      |
332  *         |  ####       |
333  *         | ####        |
334  *         |###          |
335  *       ####            |
336  *         |             |
337  *
338  */
339     AsciiSinkObject sink = (AsciiSinkObject)ctx->text.sink;
340     XawTextAnchor *anchor;
341     XawTextEntity *entity;
342     XawTextProperty *property;
343     XawTextPaintStruct *paint;
344     XawTextBlock block;
345     XFontStruct *font;
346
347     property = NULL;
348     if (XawTextSourceAnchorAndEntity(ctx->text.source, position,
349                                      &anchor, &entity) &&
350         (property = XawTextSinkGetProperty((Widget)sink,
351                                            entity->property)) != NULL &&
352         (property->mask & XAW_TPROP_FONT))
353         font = property->font;
354     else
355         font = sink->ascii_sink.font;
356     if (right) {
357         if (font->max_bounds.rbearing > 0) {
358             int rbearing = font->max_bounds.rbearing - font->max_bounds.width;
359             unsigned char c;
360
361             (void)XawTextSourceRead(ctx->text.source, position, &block, 1);
362             c = *(unsigned char*)block.ptr;
363             if (c == '\t' || c == '\n')
364                 c = ' ';
365             else if ((c & 0177) < XawSP || c == 0177) {
366                 if (sink->ascii_sink.display_nonprinting)
367                     c = c > 0177 ? (c & 7) + '0' : c + '@';
368                 else
369                     c = ' ';
370             }
371             if (font->per_char &&
372                 (c >= font->min_char_or_byte2 && c <= font->max_char_or_byte2))
373                 rbearing = font->per_char[c - font->min_char_or_byte2].rbearing -
374                            font->per_char[c - font->min_char_or_byte2].width;
375             if (rbearing > 0) {
376                 paint = XtNew(XawTextPaintStruct);
377                 paint->next = sink->text_sink.paint->bearings;
378                 sink->text_sink.paint->bearings = paint;
379                 paint->x = x - (paint->width = CharWidth(sink, font, 0, c));
380                 paint->y = y + ascent;
381                 paint->property = property;
382                 paint->max_ascent = ascent;
383                 paint->max_descent = descent;
384                 paint->backtabs = NULL;
385                 paint->highlight = highlight;
386                 paint->length = 1;
387                 paint->text = XtMalloc(1);
388                 paint->text[0] = c;
389             }
390         }
391     }
392     else {
393         if (font->min_bounds.lbearing < 0) {
394             int lbearing = font->min_bounds.lbearing;
395             unsigned char c;
396
397             (void)XawTextSourceRead(ctx->text.source, position, &block, 1);
398             c = *(unsigned char*)block.ptr;
399             if (c == '\t' || c == '\n')
400                 c = ' ';
401             else if ((c & 0177) < XawSP || c == 0177) {
402                 if (sink->ascii_sink.display_nonprinting)
403                     c = c > 0177 ? '\\' : c + '^';
404                 else
405                     c = ' ';
406             }
407             if (font->per_char &&
408                 (c >= font->min_char_or_byte2 && c <= font->max_char_or_byte2))
409                 lbearing = font->per_char[c - font->min_char_or_byte2].lbearing;
410             if (lbearing < 0) {
411                 paint = XtNew(XawTextPaintStruct);
412                 paint->next = sink->text_sink.paint->bearings;
413                 sink->text_sink.paint->bearings = paint;
414                 paint->x = x;
415                 paint->width = -CharWidth(sink, font, 0, c);
416                 paint->y = y + ascent;
417                 paint->property = property;
418                 paint->max_ascent = ascent;
419                 paint->max_descent = descent;
420                 paint->backtabs = NULL;
421                 paint->highlight = highlight;
422                 paint->length = 1;
423                 paint->text = XtMalloc(1);
424                 paint->text[0] = c;
425             }
426         }
427     }
428 }
429
430 static void
431 AsciiPreparePaint(Widget w, int y, int line,
432                   XawTextPosition from, XawTextPosition to, Bool highlight)
433 {
434     static XmuSegment segment;
435     static XmuScanline next;
436     static XmuScanline scanline = {0, &segment, &next};
437     static XmuArea area = {&scanline};
438
439     TextWidget ctx = (TextWidget)XtParent(w);
440     AsciiSinkObject sink = (AsciiSinkObject)ctx->text.sink;
441     XawTextPosition left, right, pos, pos2, tmp, length;
442     XawTextAnchor *anchor;
443     XawTextEntity *entity;
444     XawTextProperty *property;
445     int i, ascent = 0, descent = 0, xl, xr, x = ctx->text.left_margin, bufsiz;
446     XawTextBlock block;
447     XFontStruct *font;
448     XawTextPaintStruct *paint;
449
450     if (!sink->ascii_sink.echo)
451         return;
452
453     /* pass 1: calculate ascent/descent values and x coordinate */
454     /* XXX the MAX ascent/descent value should be in the line table XXX */
455     /* XXX the x coordinate can be a parameter, but since it is required
456            to calculate the ascent/descent, do it here to avoid an extra
457            search in the entities */
458     pos = tmp = left = ctx->text.lt.info[line].position;
459     right = ctx->text.lt.info[line + 1].position;
460     right = XawMin(right, ctx->text.lastPos + 1);
461     while (pos < right) {
462         if (XawTextSourceAnchorAndEntity(ctx->text.source, pos,
463                                          &anchor, &entity)) {
464             if ((property = XawTextSinkGetProperty((Widget)sink,
465                                                    entity->property)) != NULL &&
466                 (property->mask & XAW_TPROP_FONT))
467                 font = property->font;
468             else
469                 font = sink->ascii_sink.font;
470             tmp = pos;
471             pos = anchor->position + entity->offset + entity->length;
472             if ((length = XawMin(from, pos) - tmp) > 0)
473                 x += GetTextWidth(ctx, x, font, tmp, length);
474             ascent = XawMax(font->ascent, ascent);
475             descent = XawMax(font->descent, descent);
476         }
477         else if (anchor) {
478             ascent = XawMax(sink->ascii_sink.font->ascent, ascent);
479             descent = XawMax(sink->ascii_sink.font->descent, descent);
480             while (entity && pos < right) {
481                 tmp = pos;
482                 if ((pos = anchor->position + entity->offset) < tmp)
483                     pos = tmp;
484                 else {
485                     if ((length = XawMin(from, pos) - tmp) > 0) {
486                         x += GetTextWidth(ctx, x, sink->ascii_sink.font, tmp,
487                                           length);
488                         tmp += length;
489                     }
490                     if (pos < right) {
491                         pos += entity->length;
492                         if ((property = XawTextSinkGetProperty((Widget)sink,
493                                                                entity->property)) != NULL &&
494                             (property->mask & XAW_TPROP_FONT))
495                             font = property->font;
496                         else
497                             font = sink->ascii_sink.font;
498                         if ((length = XawMin(from, pos) - tmp) > 0)
499                             x += GetTextWidth(ctx, x, font, tmp, length);
500                         ascent = XawMax(font->ascent, ascent);
501                         descent = XawMax(font->descent, descent);
502                     }
503                 }
504                 entity = entity->next;
505             }
506
507             if (anchor->entities == NULL) {
508                 tmp = XawMin(pos, from);
509                 if ((length = from - tmp) > 0)
510                     x += GetTextWidth(ctx, x, sink->ascii_sink.font, tmp, length);
511                 break;
512             }
513         }
514         else {
515             tmp = XawMin(pos, from);
516             if ((length = from - tmp) > 0)
517                 x += GetTextWidth(ctx, x, sink->ascii_sink.font, tmp, length);
518             ascent = XawMax(sink->ascii_sink.font->ascent, ascent);
519             descent = XawMax(sink->ascii_sink.font->descent, descent);
520             break;
521         }
522     }
523     if (!ascent)
524         ascent = sink->ascii_sink.font->ascent;
525     if (!descent)
526         descent = sink->ascii_sink.font->descent;
527
528     xl = x;
529
530     /* pass 2: feed the XawTextPaintStruct lists */
531     pos = from;
532     while (pos < to) {
533         paint = XtNew(XawTextPaintStruct);
534         paint->next = sink->text_sink.paint->paint;
535         sink->text_sink.paint->paint = paint;
536         paint->x = x;
537         paint->y = y + ascent;
538         paint->property = NULL;
539         paint->max_ascent = ascent;
540         paint->max_descent = descent;
541         paint->backtabs = NULL;
542         paint->highlight = highlight;
543
544         tmp = pos;
545         if (XawTextSourceAnchorAndEntity(ctx->text.source, pos,
546                                          &anchor, &entity)) {
547             pos = anchor->position + entity->offset + entity->length;
548             if ((paint->property = XawTextSinkGetProperty((Widget)sink,
549                                                    entity->property)) != NULL &&
550                 (paint->property->mask & XAW_TPROP_FONT))
551                 font = paint->property->font;
552             else
553                 font = sink->ascii_sink.font;
554         }
555         else {
556             if (anchor) {
557                 while (entity && anchor->position + entity->offset < pos)
558                     entity = entity->next;
559                 if (entity)
560                     pos = anchor->position + entity->offset;
561                 else
562                     pos = to;
563             }
564             else
565                 pos = to;
566             font = sink->ascii_sink.font;
567         }
568         pos = XawMin(pos, to);
569         length = pos - tmp;
570
571         paint->text = XtMalloc(bufsiz = pos - tmp + 4);
572         paint->length = 0;
573         segment.x1 = x;
574
575         pos2 = tmp;
576         while (length > 0) {
577             pos2 = XawTextSourceRead(ctx->text.source, tmp, &block, length);
578             length = pos - pos2;
579             tmp = pos2;
580             for (i = 0; i < block.length; i++) {
581                 unsigned char c = (unsigned char)block.ptr[i];
582
583                 if (paint->length + 4 > bufsiz)
584                     paint->text = XtRealloc(paint->text, bufsiz += 32);
585                 paint->text[paint->length] = c;
586                 if (c == '\n') {
587                     x += CharWidth(sink, font, 0, ' ');
588                     continue;
589                 }
590                 if (c == '\t') {
591                     x += XTextWidth(font, paint->text, paint->length);
592                     segment.x2 = x + CharWidth(sink, font, x, '\t');
593
594                     if (XmuValidSegment(&segment)) {
595                         if (!highlight && (paint->property &&
596                             (paint->property->mask & XAW_TPROP_BACKGROUND))) {
597                             if (ascent > font->ascent) {
598                                 scanline.y = y;
599                                 next.y = y + ascent - font->ascent;
600                                 XmuAreaOr(sink->text_sink.paint->clip, &area);
601                             }
602                             if (descent >= font->descent) {
603                                 scanline.y = y + ascent + font->descent;
604                                 next.y = scanline.y + descent - font->descent + 1;
605                                 XmuAreaOr(sink->text_sink.paint->clip, &area);
606                             }
607                             if (paint->backtabs == NULL)
608                                 paint->backtabs = XmuCreateArea();
609                             scanline.y = y + ascent - font->ascent;
610                             next.y = y + ascent + font->descent;
611                             XmuAreaOr(paint->backtabs, &area);
612                         }
613                         else {
614                             scanline.y = y;
615                             next.y = ctx->text.lt.info[line + 1].y;
616                             if (highlight) {
617                                 if (!sink->text_sink.paint->hightabs)
618                                     sink->text_sink.paint->hightabs =
619                                         XmuCreateArea();
620                                 XmuAreaOr(sink->text_sink.paint->hightabs, &area);
621                             }
622                             else
623                                 XmuAreaOr(sink->text_sink.paint->clip, &area);
624                         }
625                     }
626
627                     paint->width = segment.x2 - segment.x1;
628                     x = segment.x1 = segment.x2;
629
630                     if (paint->length == 0) {
631                         paint->x = x;
632                         continue;
633                     }
634                     paint->text = XtRealloc(paint->text, paint->length);
635                     property = paint->property;
636                     paint = XtNew(XawTextPaintStruct);
637                     paint->next = sink->text_sink.paint->paint;
638                     sink->text_sink.paint->paint = paint;
639                     paint->x = x;
640                     paint->y = y + ascent;
641                     paint->property = property;
642                     paint->max_ascent = ascent;
643                     paint->max_descent = descent;
644                     paint->backtabs = NULL;
645                     paint->highlight = highlight;
646                     paint->text = XtMalloc(bufsiz = pos - tmp - length +
647                                                     block.length - i + 4);
648                     paint->length = 0;
649                     continue;
650                 }
651                 if ((c & 0177) < XawSP || c == 0177) {
652                     if (sink->ascii_sink.display_nonprinting) {
653                         if (c > 0177) {
654                             paint->text[paint->length++] = '\\';
655                             paint->text[paint->length++] = ((c >> 6) & 7) + '0';
656                             paint->text[paint->length++] = ((c >> 3) & 7) + '0';
657                             paint->text[paint->length] = (c & 7) + '0';
658                         }
659                         else {
660                             c |= 0100;
661                             paint->text[paint->length++] = '^';
662                             paint->text[paint->length] = c == 0177 ? '?' : c;
663                         }
664                     }
665                     else
666                         paint->text[paint->length] = ' ';
667                 }
668                 paint->length++;
669             }
670         }
671
672         x += XTextWidth(font, paint->text, paint->length);
673         segment.x2 = x;
674         if (XmuValidSegment(&segment)) {
675             /* erase only what really is needed */
676             /*if (!highlight || (paint->property &&
677                 (paint->property->mask & XAW_TPROP_BACKGROUND))) {
678                 if (ascent > font->ascent) {
679                     scanline.y = y;
680                     next.y = y + ascent - font->ascent;
681                     XmuAreaOr(sink->text_sink.paint->clip, &area);
682                 }
683                 if (descent > font->descent) {
684                     scanline.y = y + ascent + font->descent;
685                     next.y = scanline.y + descent - font->descent;
686                     XmuAreaOr(sink->text_sink.paint->clip, &area);
687                 }
688             }
689             else*/ {
690                 scanline.y = y;
691                 next.y = ctx->text.lt.info[line + 1].y;
692                 XmuAreaOr(sink->text_sink.paint->clip, &area);
693             }
694         }
695
696         paint->width = x - segment.x1;
697     }
698
699     xr = x;
700
701     /* pass 3: bearing clipping */
702     if (left < from) {
703         CalculateBearing(ctx, from - 1, xl, y, ascent, descent, highlight, True);
704         if (ctx->text.s.left < ctx->text.s.right) {
705             if (ctx->text.s.right == from)
706                 CalculateBearing(ctx, from, xl, y, ascent, descent, True, False);
707             else if (ctx->text.s.left == from)
708                 CalculateBearing(ctx, from, xl, y, ascent, descent, False, False);
709         }
710     }
711     right = XawMin(right, ctx->text.lastPos);
712     if (right >= to && to > from) {
713         if (to < right)
714             CalculateBearing(ctx, to, xr, y, ascent, descent, highlight, False);
715         if (ctx->text.s.left < ctx->text.s.right) {
716             if (ctx->text.s.right == to)
717                 CalculateBearing(ctx, to - 1, xr, y, ascent, descent, False, True);
718             else if (ctx->text.s.left == to)
719                 CalculateBearing(ctx, to - 1, xr, y, ascent, descent, True, True);
720         }
721     }
722 }
723
724 static int
725 qcmp_paint_struct(_Xconst void *left, _Xconst void *right)
726 {
727     return ((*(XawTextPaintStruct**)left)->property -
728             (*(XawTextPaintStruct**)right)->property);
729 }
730
731 static void
732 AsciiDoPaint(Widget w)
733 {
734     TextWidget ctx = (TextWidget)XtParent(w);
735     AsciiSinkObject sink = (AsciiSinkObject)ctx->text.sink;
736     XmuScanline *scan;
737     XmuSegment *seg;
738     XawTextPaintList *list = sink->text_sink.paint;
739 #if 0
740     XawTextPaintStruct *base, *head;
741 #endif
742     XawTextPaintStruct *paint = list->paint;
743     XawTextProperty *property;
744     XFontStruct *font = NULL;
745     XRectangle *rects;
746     int n_rects, i_rects;
747     GC gc;
748     Bool highlight;
749     XRectangle rect;
750     int width, height, line_width = -1;
751     XGCValues values;
752
753     /* pass 1: clear clipping areas */
754     /* XXX Don't use XDrawImageString because the font may be italic, and
755            will get incorrectly drawn. Probably, it could be a good idea to
756            check if this is the case, and do special processing. But this
757            will need to be checked if required. */
758     for (scan = list->clip->scanline; scan && scan->next; scan = scan->next)
759         for (seg = scan->segment; seg; seg = seg->next)
760             _XawTextSinkClearToBackground(ctx->text.sink,
761                                           seg->x1, scan->y,
762                                           seg->x2 - seg->x1,
763                                           scan->next->y - scan->y);
764
765     /* pass 2: optimize drawing list to avoid too much GC change requests */
766     /* XXX this assumes there will not exist entities drawn over other
767            entities. */
768 #if 0
769     while (paint) {
770         base = paint;
771         head = paint->next;
772         while (head) {
773             if (head->property == paint->property) {
774                 base->next = head->next;
775                 head->next = paint->next;
776                 paint->next = head;
777                 paint = head;
778             }
779             base = head;
780             head = head->next;
781         }
782         paint = paint->next;
783     }
784 #endif
785     if (paint && paint->next) {
786         XawTextPaintStruct **paints;
787         int i = 0, n_paints = 0;
788
789         while (paint) {
790             paint = paint->next;
791             ++n_paints;
792         }
793         paints = (XawTextPaintStruct**)
794             XtMalloc(n_paints * sizeof(XawTextPaintStruct));
795         paint = list->paint;
796         while (paint) {
797             paints[i++] = paint;
798             paint = paint->next;
799         }
800         qsort((void*)paints, n_paints, sizeof(XawTextPaintStruct*),
801               qcmp_paint_struct);
802         list->paint = paints[0];
803         for (i = 0; i < n_paints - 1; i++)
804             paints[i]->next = paints[i + 1];
805         paints[i]->next = NULL;
806         XtFree((XtPointer)paints);
807     }
808
809     /* pass 3: clip gc */
810     gc = sink->ascii_sink.normgc;
811
812     rect.x = ctx->text.r_margin.left;
813     rect.y = ctx->text.r_margin.top;
814     width = (int)XtWidth(ctx) - RHMargins(ctx);
815     height = (int)XtHeight(ctx) - RVMargins(ctx);
816     rect.width = width;
817     rect.height = height;
818     if (width >= 0 && height >= 0)
819         XSetClipRectangles(XtDisplay((Widget)ctx), gc,
820                            0, 0, &rect, 1, Unsorted);
821     else
822         XSetClipMask(XtDisplay((Widget)ctx), gc, None);
823
824     /* pass 4: draw backgrounds */
825     paint = list->paint;
826     property = NULL;
827     rects = NULL;
828     i_rects = n_rects = 0;
829     while (paint) {
830         if (paint->property && (paint->property->mask & XAW_TPROP_BACKGROUND)) {
831             if (property != paint->property) {
832                 if (i_rects)
833                     XFillRectangles(XtDisplay(ctx), XtWindow(ctx), gc,
834                                     rects, i_rects);
835                 i_rects = 0;
836                 property = paint->property;
837                 if (property->mask & XAW_TPROP_FONT)
838                     font = property->font;
839                 else
840                     font = sink->ascii_sink.font;
841                 XSetForeground(XtDisplay(ctx), gc, property->background);
842             }
843             if (i_rects <= n_rects)
844                 rects = (XRectangle*)
845                     XtRealloc((XtPointer)rects, sizeof(XRectangle) *
846                               ++n_rects);
847             rects[i_rects].x = paint->x;
848             rects[i_rects].y = paint->y - font->ascent;
849             rects[i_rects].width = paint->width;
850             rects[i_rects++].height = font->ascent + font->descent;
851
852             if (paint->backtabs) {
853                 for (scan = paint->backtabs->scanline; scan && scan->next;
854                      scan = scan->next)
855                     for (seg = scan->segment; seg; seg = seg->next) {
856                         if (i_rects <= n_rects)
857                             rects = (XRectangle*)
858                                 XtRealloc((XtPointer)rects, sizeof(XRectangle) *
859                                           ++n_rects);
860                         rects[i_rects].x = seg->x1;
861                         rects[i_rects].y = scan->y;
862                         rects[i_rects].width = seg->x2 - seg->x1;
863                         rects[i_rects++].height = scan->next->y - scan->y;
864                     }
865             }
866
867
868         }
869         paint = paint->next;
870     }
871     if (i_rects)
872         XFillRectangles(XtDisplay(ctx), XtWindow(ctx), gc, rects, i_rects);
873
874     paint = list->paint;
875     i_rects = 0;
876     while (paint) {
877         if (paint->highlight) {
878             if (i_rects == 0)
879                 XSetForeground(XtDisplay(ctx), gc, sink->text_sink.cursor_color);
880             if (i_rects <= n_rects)
881                 rects = (XRectangle*)
882                     XtRealloc((XtPointer)rects, sizeof(XRectangle) *
883                               ++n_rects);
884             rects[i_rects].x = paint->x;
885             rects[i_rects].y = paint->y - paint->max_ascent;
886             rects[i_rects].width = paint->width;
887             rects[i_rects++].height = paint->max_ascent + paint->max_descent + 1;
888         }
889         paint = paint->next;
890     }
891     if (list->hightabs) {
892         for (scan = list->hightabs->scanline; scan && scan->next;
893              scan = scan->next)
894             for (seg = scan->segment; seg; seg = seg->next) {
895                 if (i_rects == 0)
896                     XSetForeground(XtDisplay(ctx), gc,
897                                    sink->text_sink.cursor_color);
898                 if (i_rects <= n_rects)
899                     rects = (XRectangle*)
900                         XtRealloc((XtPointer)rects, sizeof(XRectangle) *
901                                   ++n_rects);
902                 rects[i_rects].x = seg->x1;
903                 rects[i_rects].y = scan->y;
904                 rects[i_rects].width = seg->x2 - seg->x1;
905                 rects[i_rects++].height = scan->next->y - scan->y;
906             }
907     }
908
909     if (i_rects)
910         XFillRectangles(XtDisplay(ctx), XtWindow(ctx), gc, rects, i_rects);
911     if (rects)
912         XtFree((XtPointer)rects);
913
914     /* pass 5: draw text! */
915     paint = list->paint;
916     if (paint && (property = paint->property) == NULL) {
917         font = sink->ascii_sink.font;
918         XSetFont(XtDisplay(ctx), gc, font->fid);
919         if (!paint->highlight)
920             XSetForeground(XtDisplay(ctx), gc, sink->text_sink.foreground);
921     }
922     else
923         property = NULL;
924     highlight = False;
925     while (paint) {
926         if (!highlight && paint->highlight)
927             XSetForeground(XtDisplay(ctx), gc, sink->text_sink.background);
928         if (highlight || paint->highlight || paint->property != property) {
929             if (!paint->property || !(paint->property->mask & XAW_TPROP_FONT))
930                 font = sink->ascii_sink.font;
931             else
932                 font = paint->property->font;
933             XSetFont(XtDisplay(ctx), gc, font->fid);
934             if (!paint->highlight) {
935                 if (!paint->property ||
936                     !(paint->property->mask & XAW_TPROP_FOREGROUND))
937                     XSetForeground(XtDisplay(ctx), gc,
938                                    sink->text_sink.foreground);
939                 else
940                     XSetForeground(XtDisplay(ctx), gc,
941                                    paint->property->foreground);
942             }
943             highlight = paint->highlight;
944             property = paint->property;
945         }
946
947         if (paint->x < XtWidth(ctx) && paint->x + paint->width > 0) {
948             XDrawString(XtDisplay(ctx), XtWindow(ctx), gc, paint->x, paint->y,
949                         paint->text, paint->length);
950             if (property) {
951                 if (property->mask & XAW_TPROP_UNDERLINE) {
952                     if (line_width != property->underline_thickness) {
953                         values.line_width = line_width =
954                             property->underline_thickness;
955                         XChangeGC(XtDisplay(ctx), gc, GCLineWidth, &values);
956                     }
957
958                     XDrawLine(XtDisplay(ctx), XtWindow(ctx), gc, paint->x,
959                               paint->y + property->underline_position,
960                               paint->x + paint->width,
961                               paint->y + property->underline_position);
962                 }
963                 if (property->mask & XAW_TPROP_OVERSTRIKE) {
964                     if (line_width != property->underline_thickness) {
965                         values.line_width = line_width =
966                             property->underline_thickness;
967                         XChangeGC(XtDisplay(ctx), gc, GCLineWidth, &values);
968                     }
969
970                     XDrawLine(XtDisplay(ctx), XtWindow(ctx), gc, paint->x,
971                               paint->y - (font->ascent>>1) + (font->descent>>1),
972                               paint->x + paint->width,
973                               paint->y - (font->ascent>>1) + (font->descent>>1));
974                 }
975             }
976         }
977
978         paint = paint->next;
979     }
980
981     /* pass 6: bearing clipping */
982     /* dont care on order of drawing or caching of state (by now) */
983     paint = list->bearings;
984     while (paint) {
985         XRectangle rect;
986
987         if (paint->highlight)
988             XSetForeground(XtDisplay(ctx), gc, sink->text_sink.background);
989         if (!paint->property || !(paint->property->mask & XAW_TPROP_FONT))
990             font = sink->ascii_sink.font;
991         else
992             font = paint->property->font;
993         XSetFont(XtDisplay(ctx), gc, font->fid);
994         if (!paint->highlight) {
995             if (!paint->property ||
996                 !(paint->property->mask & XAW_TPROP_FOREGROUND))
997                 XSetForeground(XtDisplay(ctx), gc, sink->text_sink.foreground);
998             else
999                 XSetForeground(XtDisplay(ctx), gc, paint->property->foreground);
1000         }
1001         if (paint->x < XtWidth(ctx) && paint->x + paint->width > 0) {
1002             rect.x = paint->x + paint->width;
1003             rect.width = XawAbs(paint->width);      /* more than enough */
1004             rect.y = paint->y - font->ascent;
1005             rect.height = rect.y + font->ascent + font->descent;
1006             XSetClipRectangles(XtDisplay((Widget)ctx), gc,
1007                                0, 0, &rect, 1, Unsorted);
1008             XDrawString(XtDisplay(ctx), XtWindow(ctx), gc, paint->x, paint->y,
1009                         paint->text, paint->length);
1010         }
1011         paint = paint->next;
1012     }
1013 }
1014 #endif
1015
1016 /*
1017  * Function:
1018  *      PaintText
1019  *
1020  * Parameters:
1021  *      w   - text sink object
1022  *      gc  - gc to paint text with
1023  *      x   - location to paint the text
1024  *      y   - ""
1025  *      buf - buffer and length of text to paint.
1026  *      len - ""
1027  *      clear_bg - clear background before drawing ?
1028  *
1029  * Description:
1030  *      Actually paints the text into the window.
1031  *
1032  * Returns:
1033  *      the width of the text painted
1034  */
1035 static unsigned int
1036 PaintText(Widget w, GC gc, int x, int y, char *buf, int len, Bool clear_bg)
1037 {
1038     AsciiSinkObject sink = (AsciiSinkObject)w;
1039     TextWidget ctx = (TextWidget)XtParent(w);
1040     int width = XTextWidth(sink->ascii_sink.font, buf, len);
1041
1042     if ((x > XtWidth(ctx)) || width <= -x) /* Don't draw if we can't see it */
1043         return (width);
1044
1045     if (clear_bg) {
1046         _XawTextSinkClearToBackground(w, x, y - sink->ascii_sink.font->ascent,
1047                                      width, sink->ascii_sink.font->ascent
1048                                      + sink->ascii_sink.font->descent);
1049         XDrawString(XtDisplay(ctx), XtWindow(ctx), gc, x, y, buf, len);
1050     }
1051     else
1052         XDrawImageString(XtDisplay(ctx), XtWindow(ctx), gc, x, y, buf, len);
1053
1054     return (width);
1055 }
1056
1057 static void
1058 DisplayText(Widget w, int x, int y,
1059             XawTextPosition pos1, XawTextPosition pos2, Bool highlight)
1060 {
1061     TextWidget ctx = (TextWidget)XtParent(w);
1062     AsciiSinkObject sink = (AsciiSinkObject)w;
1063     XFontStruct *font = sink->ascii_sink.font;
1064     Widget source = XawTextGetSource(XtParent(w));
1065     unsigned char buf[260];
1066     int j, k;
1067     XawTextBlock blk;
1068     GC gc, invgc, tabgc;
1069     int max_x;
1070     Bool clear_bg;
1071
1072     if (!sink->ascii_sink.echo || !ctx->text.lt.lines)
1073         return;
1074
1075     max_x = (int)XtWidth(ctx) - ctx->text.r_margin.right;
1076     clear_bg = !highlight && ctx->core.background_pixmap != XtUnspecifiedPixmap;
1077
1078     gc = highlight ? sink->ascii_sink.invgc : sink->ascii_sink.normgc;
1079     invgc = highlight ? sink->ascii_sink.normgc : sink->ascii_sink.invgc;
1080
1081     if (highlight && sink->ascii_sink.xorgc)
1082         tabgc = sink->ascii_sink.xorgc;
1083     else
1084         tabgc = invgc;
1085
1086     y += sink->ascii_sink.font->ascent;
1087     for (j = 0; pos1 < pos2;) {
1088         pos1 = XawTextSourceRead(source, pos1, &blk, pos2 - pos1);
1089         for (k = 0; k < blk.length; k++) {
1090             if (j >= sizeof(buf) - 4) { /* buffer full, dump the text */
1091                 if ((x += PaintText(w, gc, x, y, (char*)buf, j, clear_bg))
1092                     >= max_x)
1093                     return;
1094                 j = 0;
1095             }
1096             buf[j] = blk.ptr[k];
1097             if (buf[j] == XawLF)        /* line feeds ('\n') are not printed */
1098                 continue;
1099
1100             else if (buf[j] == '\t') {
1101                 int width;
1102
1103                 if (j != 0
1104                     && (x += PaintText(w, gc, x, y, (char*)buf, j, clear_bg))
1105                     >= max_x)
1106                     return;
1107
1108                 if ((width = CharWidth(sink, font, x, '\t')) > -x) {
1109                     if (clear_bg)
1110                         _XawTextSinkClearToBackground(w, x, y-font->ascent, width,
1111                                                       font->ascent+font->descent);
1112                     else
1113                         XFillRectangle(XtDisplayOfObject(w), XtWindowOfObject(w),
1114                                        tabgc, x, y - font->ascent, width,
1115                                        font->ascent + font->descent);
1116                 }
1117
1118                 if ((x += width) >= max_x)
1119                     return;
1120
1121                 j = -1;
1122             }
1123             else if ((buf[j] & 0177) < XawSP || buf[j] == 0177) {
1124                 if (sink->ascii_sink.display_nonprinting) {
1125                     unsigned char c = buf[j];
1126
1127                     if (c > 0177) {
1128                         buf[j++] = '\\';
1129                         buf[j++] = ((c >> 6) & 7) + '0';
1130                         buf[j++] = ((c >> 3) & 7) + '0';
1131                         buf[j] = (c & 7) + '0';
1132                     }
1133                     else {
1134                         c |= 0100;
1135                         buf[j++] = '^';
1136                         buf[j] = c == 0177 ? '?' : c;
1137                     }
1138                 }
1139                 else
1140                   buf[j] = ' ';
1141             }
1142             j++;
1143         }
1144     }
1145
1146     if (j > 0)
1147         (void)PaintText(w, gc, x, y, (char*)buf, j, clear_bg);
1148 }
1149
1150 /*
1151  * Function:
1152  *      GetCursorBounds
1153  *
1154  * Parameters:
1155  *      w - text sink object
1156  *      rect - X rectangle to return the cursor bounds
1157  *
1158  * Description:
1159  *      Returns the size and location of the cursor.
1160  */
1161 static void
1162 GetCursorBounds(Widget w, XRectangle *rect)
1163 {
1164     AsciiSinkObject sink = (AsciiSinkObject)w;
1165     XFontStruct *font = sink->ascii_sink.font;
1166     unsigned char ch;
1167 #ifndef OLDXAW
1168     TextWidget ctx = (TextWidget)XtParent(w);
1169     XawTextBlock block;
1170     XawTextAnchor *anchor;
1171     XawTextEntity *entity;
1172     XawTextProperty *property;
1173
1174     if (XawTextSourceAnchorAndEntity(XawTextGetSource(XtParent(w)),
1175                                      sink->ascii_sink.cursor_position,
1176                                      &anchor, &entity)) {
1177         if ((property = XawTextSinkGetProperty((Widget)sink,
1178                                                entity->property)) != NULL &&
1179             (property->mask & XAW_TPROP_FONT))
1180             font = property->font;
1181     }
1182     (void)XawTextSourceRead(XawTextGetSource((Widget)ctx),
1183                             ctx->text.insertPos, &block, 1);
1184     if (!block.length || block.ptr[0] == '\n' || block.ptr[0] == '\t')
1185         ch = ' ';
1186     else if ((*((unsigned char*)block.ptr) & 0177) < XawSP ||
1187         *(unsigned char*)block.ptr == 0177) {
1188         if (sink->ascii_sink.display_nonprinting)
1189             ch = *((unsigned char*)block.ptr) > 0177 ? '\\' : '^';
1190         else
1191             ch = ' ';
1192     }
1193     else
1194         ch = *(unsigned char*)block.ptr;
1195 #else
1196     ch = ' ';
1197 #endif
1198
1199     rect->width = CharWidth(sink, font, 0, ch);
1200     rect->height = font->descent + font->ascent + 1;
1201
1202     rect->x = sink->ascii_sink.cursor_x;
1203     rect->y = sink->ascii_sink.cursor_y - font->ascent;
1204 }
1205
1206 /* this function is required to support diferent fonts and correctly place
1207  * the cursor. There are better ways to calculate the base line, but there is
1208  * no place/code (yet) to store this information.
1209  */
1210 static int
1211 FindCursorY(TextWidget ctx, XawTextPosition position)
1212 {
1213     int y, line, ascent;
1214     AsciiSinkObject sink = (AsciiSinkObject)ctx->text.sink;
1215 #ifndef OLDXAW
1216     XawTextAnchor *anchor;
1217     XawTextEntity *entity;
1218     XawTextProperty *property;
1219     XawTextPosition left, right;
1220 #endif
1221
1222     for (line = 0; line < ctx->text.lt.lines; line++)
1223         if (position < ctx->text.lt.info[line + 1].position)
1224             break;
1225
1226     y = ctx->text.lt.info[line].y;
1227 #ifndef OLDXAW
1228     ascent = 0;
1229     left = ctx->text.lt.info[line].position;
1230     right = ctx->text.lt.info[line + 1].position;
1231     right = XawMin(right, ctx->text.lastPos + 1);
1232     while (left < right) {
1233         if (XawTextSourceAnchorAndEntity(ctx->text.source, left,
1234                                          &anchor, &entity)) {
1235             if ((property = XawTextSinkGetProperty((Widget)sink,
1236                                                    entity->property)) != NULL &&
1237                 (property->mask & XAW_TPROP_FONT))
1238                 ascent = XawMax(property->font->ascent, ascent);
1239             else
1240                 ascent = XawMax(sink->ascii_sink.font->ascent, ascent);
1241             left = anchor->position + entity->offset + entity->length;
1242         }
1243         else if (anchor) {
1244             ascent = XawMax(sink->ascii_sink.font->ascent, ascent);
1245             while (entity) {
1246                 XawTextPosition tmp = anchor->position + entity->offset + entity->length;
1247
1248                 if (tmp > left && tmp < right) {
1249                     left = tmp;
1250                     if ((property = XawTextSinkGetProperty((Widget)sink,
1251                                                            entity->property)) != NULL &&
1252                         (property->mask & XAW_TPROP_FONT))
1253                         ascent = XawMax(property->font->ascent, ascent);
1254                     else
1255                         ascent = XawMax(sink->ascii_sink.font->ascent, ascent);
1256                 }
1257                 entity = entity->next;
1258             }
1259             if (entity == NULL)
1260                 break;
1261         }
1262         else {
1263             ascent = XawMax(sink->ascii_sink.font->ascent, ascent);
1264             break;
1265         }
1266     }
1267     if (!ascent)
1268         ascent = sink->ascii_sink.font->ascent;
1269 #else
1270     ascent = sink->ascii_sink.font->ascent;
1271 #endif
1272
1273     return (y + ascent);
1274 }
1275
1276 static void
1277 InsertCursor(Widget w, int x, int y, XawTextInsertState state)
1278 {
1279     AsciiSinkObject sink = (AsciiSinkObject)w;
1280     XFontStruct *font = sink->ascii_sink.font;
1281     TextWidget ctx = (TextWidget)XtParent(w);
1282     XawTextPosition position = XawTextGetInsertionPoint((Widget)ctx);
1283     Boolean overflow = (x & 0xffff8000) != 0;
1284 #ifndef OLDXAW
1285     XawTextAnchor *anchor;
1286     XawTextEntity *entity;
1287     XawTextProperty *property;
1288 #endif
1289
1290     if (XtIsRealized((Widget)ctx)) {
1291         int fheight;
1292         XawTextBlock block;
1293         XawTextPosition selection_start, selection_end;
1294         Boolean has_selection;
1295
1296         if (!sink->ascii_sink.echo) {
1297             if (sink->ascii_sink.laststate != state) {
1298                 int width = CharWidth(sink, font, 0, ' ') - 1;
1299
1300                 x = ctx->text.margin.left;
1301                 y = ctx->text.margin.top;
1302                 font = sink->ascii_sink.font;
1303                 fheight = font->ascent + font->descent;
1304                 if (state == XawisOn) {
1305                     if (ctx->text.hasfocus)
1306                     XFillRectangle(XtDisplay(ctx), XtWindow(ctx),
1307                                    sink->ascii_sink.xorgc, x, y,
1308                                    width + 1, fheight + 1);
1309                     else
1310                         XDrawRectangle(XtDisplay(ctx), XtWindow(ctx),
1311                                        sink->ascii_sink.xorgc, x, y,
1312                                        width, fheight);
1313
1314                 }
1315                 else
1316                     _XawTextSinkClearToBackground(w, x, y,
1317                                                   width + 1, fheight + 1);
1318             }
1319             sink->ascii_sink.cursor_x = x;
1320             sink->ascii_sink.cursor_y = y;
1321             sink->ascii_sink.laststate = state;
1322             return;
1323         }
1324
1325
1326         XawTextGetSelectionPos((Widget)ctx, &selection_start, &selection_end);
1327         has_selection = selection_start != selection_end;
1328
1329         if (sink->ascii_sink.laststate != state) {
1330             unsigned char ch;
1331
1332 #ifndef OLDXAW
1333             if (XawTextSourceAnchorAndEntity(ctx->text.source,
1334                                              position, &anchor, &entity) &&
1335                 (property = XawTextSinkGetProperty((Widget)sink,
1336                                                    entity->property)) != NULL &&
1337                 (property->mask & XAW_TPROP_FONT))
1338                 font = property->font;
1339             else
1340                 font = sink->ascii_sink.font;
1341 #endif
1342
1343             fheight = font->ascent + font->descent;
1344             (void)XawTextSourceRead(XawTextGetSource((Widget)ctx),
1345                                     position, &block, 1);
1346             if (!block.length || block.ptr[0] == '\n' || block.ptr[0] == '\t')
1347                 ch = ' ';
1348             else if ((*((unsigned char*)block.ptr) & 0177) < XawSP
1349                 || *(unsigned char*)block.ptr == 0177) {
1350                 if (sink->ascii_sink.display_nonprinting)
1351                     ch = *((unsigned char*)block.ptr) > 0177 ? '\\' : '^';
1352                 else
1353                     ch = ' ';
1354             }
1355             else
1356                 ch = *(unsigned char*)block.ptr;
1357
1358             y = FindCursorY(ctx, position);
1359             if (ctx->text.hasfocus && !has_selection)
1360                 XFillRectangle(XtDisplay(ctx), XtWindow(ctx),
1361                                sink->ascii_sink.xorgc, x, y - font->ascent,
1362                                CharWidth(sink, font, 0, ch), fheight + 1);
1363             else
1364                 XDrawRectangle(XtDisplay(ctx), XtWindow(ctx),
1365                                sink->ascii_sink.xorgc, x, y - font->ascent,
1366                                CharWidth(sink, font, 0, ch) - 1, fheight);
1367         }
1368     }
1369
1370     sink->ascii_sink.cursor_x = overflow ? -16384 : x;
1371     sink->ascii_sink.cursor_y = y;
1372     sink->ascii_sink.laststate = state;
1373     sink->ascii_sink.cursor_position = position;
1374 }
1375
1376 /*
1377  * Given two positions, find the distance between them
1378  */
1379 static void
1380 FindDistance(Widget w, XawTextPosition fromPos, int fromx,
1381              XawTextPosition toPos, int *resWidth,
1382              XawTextPosition *resPos, int *resHeight)
1383 {
1384 #ifndef OLDXAW
1385     AsciiSinkObject sink = (AsciiSinkObject)w;
1386     TextWidget ctx = (TextWidget)XtParent(w);
1387     XFontStruct *font = sink->ascii_sink.font;
1388     Widget source = ctx->text.source;
1389     XawTextPosition idx, pos;
1390     unsigned char c;
1391     XawTextBlock blk;
1392     int i, rWidth, ascent = 0, descent = 0;
1393     XawTextAnchor *anchor;
1394     XawTextEntity *entity;
1395     XawTextProperty *property;
1396     Cardinal length;
1397     Bool done = False;
1398
1399     pos = idx = fromPos;
1400     rWidth = 0;
1401     c = 0;
1402
1403     while (!done) {
1404         if (XawTextSourceAnchorAndEntity(source, pos, &anchor, &entity)) {
1405             length = anchor->position + entity->offset + entity->length;
1406             length = XawMin(toPos, length) - pos;
1407             if ((property = XawTextSinkGetProperty((Widget)sink,
1408                                                    entity->property)) != NULL &&
1409                 (property->mask & XAW_TPROP_FONT))
1410                 font = property->font;
1411             else
1412                 font = sink->ascii_sink.font;
1413         }
1414         else {
1415             if (anchor) {
1416                 while (entity && anchor->position + entity->offset < pos)
1417                     entity = entity->next;
1418                 if (entity) {
1419                     length = anchor->position + entity->offset;
1420                     length = XawMin(toPos, length) - pos;
1421                 }
1422                 else
1423                     length = XawMin(toPos - pos, 4096);
1424             }
1425             else
1426                 length = XawMin(toPos - pos, 4096);
1427             font = sink->ascii_sink.font;
1428         }
1429
1430         ascent = XawMax(font->ascent, ascent);
1431         descent = XawMax(font->descent, descent);
1432
1433         pos = XawTextSourceRead(source, pos, &blk, length);
1434         if (blk.length == 0 && pos == idx)      /* eof reached */
1435             break;
1436
1437         idx = blk.firstPos;
1438         for (i = 0; idx < toPos; i++, idx++) {
1439             if (i >= blk.length)
1440                 break;
1441             c = blk.ptr[i];
1442             rWidth += CharWidth(sink, font, fromx + rWidth, c);
1443             if (c == XawLF) {
1444                 idx++;
1445                 done = True;
1446                 break;
1447             }
1448         }
1449         if (idx >= toPos)
1450             break;
1451     }
1452
1453     *resPos = idx;
1454     *resWidth = rWidth;
1455     *resHeight = ascent + descent + 1;
1456 #else
1457     AsciiSinkObject sink = (AsciiSinkObject)w;
1458     TextWidget ctx = (TextWidget)XtParent(w);
1459     XFontStruct *font = sink->ascii_sink.font;
1460     Widget source = ctx->text.source;
1461     XawTextPosition idx, pos;
1462     unsigned char c;
1463     XawTextBlock blk;
1464     int i, rWidth;
1465
1466     pos = XawTextSourceRead(source, fromPos, &blk, toPos - fromPos);
1467     rWidth = 0;
1468     for (i = 0, idx = fromPos; idx < toPos; i++, idx++) {
1469         if (i >= blk.length) {
1470             i = 0;
1471             pos = XawTextSourceRead(source, pos, &blk, toPos - pos);
1472             if (blk.length == 0)
1473                 break;
1474         }
1475         c = blk.ptr[i];
1476         rWidth += CharWidth(sink, font, fromx + rWidth, c);
1477         if (c == XawLF) {
1478             idx++;
1479             break;
1480         }
1481     }
1482
1483     *resPos = idx;
1484     *resWidth = rWidth;
1485     *resHeight = font->ascent + font->descent + 1;
1486 #endif
1487 }
1488
1489 static void
1490 FindPosition(Widget w, XawTextPosition fromPos, int fromx, int width,
1491              Bool stopAtWordBreak, XawTextPosition *resPos,
1492              int *resWidth, int *resHeight)
1493 {
1494 #ifndef OLDXAW
1495     AsciiSinkObject sink = (AsciiSinkObject)w;
1496     TextWidget ctx = (TextWidget)XtParent(w);
1497     Widget source = ctx->text.source;
1498     XFontStruct *font = sink->ascii_sink.font;
1499     XawTextPosition idx, pos, whiteSpacePosition = 0;
1500     int i, lastWidth, whiteSpaceWidth, rWidth, ascent = 0, descent = 0;
1501     Boolean whiteSpaceSeen;
1502     unsigned char c;
1503     XawTextBlock blk;
1504     XawTextAnchor *anchor;
1505     XawTextEntity *entity;
1506     XawTextProperty *property;
1507     Cardinal length;
1508     Bool done = False;
1509
1510     pos = idx = fromPos;
1511     rWidth = lastWidth = whiteSpaceWidth = 0;
1512     whiteSpaceSeen = False;
1513     c = 0;
1514
1515     while (!done) {
1516         font = sink->ascii_sink.font;
1517         if (XawTextSourceAnchorAndEntity(source, pos, &anchor, &entity)) {
1518             length = anchor->position + entity->offset + entity->length - pos;
1519             if ((property = XawTextSinkGetProperty((Widget)sink,
1520                                                    entity->property)) != NULL &&
1521                 (property->mask & XAW_TPROP_FONT))
1522                 font = property->font;
1523         }
1524         else {
1525             if (anchor) {
1526                 while (entity && anchor->position + entity->offset < pos)
1527                     entity = entity->next;
1528                 if (entity)
1529                     length = anchor->position + entity->offset - pos;
1530                 else
1531                     length = 4096;
1532             }
1533             else
1534                 length = 4096;
1535         }
1536
1537         ascent = XawMax(font->ascent, ascent);
1538         descent = XawMax(font->descent, descent);
1539
1540         pos = XawTextSourceRead(source, pos, &blk, length);
1541         if (blk.length == 0 && pos == idx)      /* eof reached */
1542             break;
1543
1544         idx = blk.firstPos;
1545         for (i = 0; rWidth <= width && i < blk.length; i++, idx++) {
1546             c = blk.ptr[i];
1547             lastWidth = rWidth;
1548             rWidth += CharWidth(sink, font, fromx + rWidth, c);
1549
1550             if (c == XawLF) {
1551                 idx++;
1552                 done = True;
1553                 break;
1554             }
1555             else if ((c == XawSP || c == XawTAB) && rWidth <= width) {
1556                 whiteSpaceSeen = True;
1557                 whiteSpacePosition = idx;
1558                 whiteSpaceWidth = rWidth;
1559             }
1560         }
1561         if (rWidth > width)
1562             break;
1563     }
1564
1565     if (rWidth > width && idx > fromPos) {
1566         idx--;
1567         rWidth = lastWidth;
1568         if (stopAtWordBreak && whiteSpaceSeen) {
1569             idx = whiteSpacePosition + 1;
1570             rWidth = whiteSpaceWidth;
1571         }
1572     }
1573
1574     if (idx >= ctx->text.lastPos && c != XawLF)
1575         idx = ctx->text.lastPos + 1;
1576
1577     *resPos = idx;
1578     *resWidth = rWidth;
1579     *resHeight = ascent + descent + 1;
1580 #else
1581     AsciiSinkObject sink = (AsciiSinkObject)w;
1582     TextWidget ctx = (TextWidget)XtParent(w);
1583     Widget source = ctx->text.source;
1584     XFontStruct *font = sink->ascii_sink.font;
1585     XawTextPosition idx, pos, whiteSpacePosition = 0;
1586     int i, lastWidth, whiteSpaceWidth, rWidth;
1587     Boolean whiteSpaceSeen;
1588     unsigned char c;
1589     XawTextBlock blk;
1590
1591     pos = XawTextSourceRead(source, fromPos, &blk, BUFSIZ);
1592     rWidth = lastWidth = whiteSpaceWidth = 0;
1593     whiteSpaceSeen = False;
1594     c = 0;
1595
1596     for (i = 0, idx = fromPos; rWidth <= width; i++, idx++) {
1597         if (i >= blk.length) {
1598             i = 0;
1599             pos = XawTextSourceRead(source, pos, &blk, BUFSIZ);
1600             if (blk.length == 0)
1601                 break;
1602         }
1603         c = blk.ptr[i];
1604         lastWidth = rWidth;
1605         rWidth += CharWidth(sink, font, fromx + rWidth, c);
1606
1607         if (c == XawLF) {
1608             idx++;
1609             break;
1610         }
1611         else if ((c == XawSP || c == XawTAB) && rWidth <= width) {
1612             whiteSpaceSeen = True;
1613             whiteSpacePosition = idx;
1614             whiteSpaceWidth = rWidth;
1615         }
1616     }
1617
1618     if (rWidth > width && idx > fromPos) {
1619         idx--;
1620         rWidth = lastWidth;
1621         if (stopAtWordBreak && whiteSpaceSeen) {
1622             idx = whiteSpacePosition + 1;
1623             rWidth = whiteSpaceWidth;
1624         }
1625     }
1626
1627     if (idx >= ctx->text.lastPos && c != XawLF)
1628         idx = ctx->text.lastPos + 1;
1629
1630     *resPos = idx;
1631     *resWidth = rWidth;
1632     *resHeight = font->ascent + font->descent + 1;
1633 #endif
1634 }
1635
1636 static void
1637 Resolve(Widget w, XawTextPosition pos, int fromx, int width,
1638         XawTextPosition *pos_return)
1639 {
1640     int resWidth, resHeight;
1641     Widget source = XawTextGetSource(XtParent(w));
1642
1643     FindPosition(w, pos, fromx, width, False, pos_return, &resWidth, &resHeight);
1644     if (*pos_return > GETLASTPOS)
1645         *pos_return = GETLASTPOS;
1646 }
1647
1648 static void
1649 GetGC(AsciiSinkObject sink)
1650 {
1651     XtGCMask valuemask = (GCFont | GCGraphicsExposures | GCClipXOrigin |
1652                           GCForeground | GCBackground);
1653     XGCValues values;
1654
1655     /* XXX We dont want do share a gc that will change the clip-mask */
1656     values.clip_x_origin = (long)sink;
1657     values.clip_mask = None;
1658     values.font = sink->ascii_sink.font->fid;
1659     values.graphics_exposures = False;
1660
1661     values.foreground = sink->text_sink.foreground;
1662     values.background = sink->text_sink.background;
1663     sink->ascii_sink.normgc = XtAllocateGC((Widget)sink, 0, valuemask, &values,
1664                                            GCClipMask | GCFont | GCForeground |
1665                                            GCBackground, 0);
1666
1667     values.foreground = sink->text_sink.background;
1668 #ifndef OLDXAW
1669     values.background = sink->text_sink.cursor_color;
1670 #else
1671     values.background = sink->text_sink.foreground;
1672 #endif
1673     sink->ascii_sink.invgc = XtAllocateGC((Widget)sink, 0, valuemask, &values,
1674                                           GCClipMask | GCFont, 0);
1675
1676     valuemask |= GCFunction;
1677     values.function = GXxor;
1678 #ifndef OLDXAW
1679     values.foreground = sink->text_sink.background ^ sink->text_sink.cursor_color;
1680 #else
1681     values.foreground = sink->text_sink.background ^ sink->text_sink.foreground;
1682 #endif
1683     values.background = 0L;
1684     sink->ascii_sink.xorgc = XtAllocateGC((Widget)sink, 0, valuemask,
1685                                           &values, GCClipMask | GCFont, 0);
1686
1687     XawAsciiSinkResize((Widget)sink);
1688 }
1689
1690 /* Function:
1691  *      XawAsciiSinkInitialize
1692  *
1693  * Parameters:
1694  *      request - the requested and new values for the object instance
1695  *      cnew    - ""
1696  *
1697  * Description:
1698  *      Initializes the TextSink Object.
1699  */
1700 /*ARGSUSED*/
1701 static void
1702 XawAsciiSinkInitialize(Widget request, Widget cnew,
1703                        ArgList args, Cardinal *num_args)
1704 {
1705     AsciiSinkObject sink = (AsciiSinkObject)cnew;
1706
1707     GetGC(sink);
1708
1709     if (!sink->ascii_sink.font) XtError("Aborting: no font found\n");
1710
1711     sink->ascii_sink.cursor_position = 0;
1712     sink->ascii_sink.laststate = XawisOff;
1713     sink->ascii_sink.cursor_x = sink->ascii_sink.cursor_y = 0;
1714 }
1715
1716 /*
1717  * Function:
1718  *      XawAsciiSinkDestroy
1719  *
1720  * Parameters:
1721  *      w - AsciiSink Object
1722  *
1723  * Description:
1724  *      This function cleans up when the object is destroyed.
1725  */
1726 static void
1727 XawAsciiSinkDestroy(Widget w)
1728 {
1729     AsciiSinkObject sink = (AsciiSinkObject)w;
1730
1731     XtReleaseGC(w, sink->ascii_sink.normgc);
1732     XtReleaseGC(w, sink->ascii_sink.invgc);
1733     XtReleaseGC(w, sink->ascii_sink.xorgc);
1734
1735     sink->ascii_sink.normgc =
1736       sink->ascii_sink.invgc =
1737       sink->ascii_sink.xorgc = NULL;
1738 }
1739
1740 static void
1741 XawAsciiSinkResize(Widget w)
1742 {
1743     TextWidget ctx = (TextWidget)XtParent(w);
1744     AsciiSinkObject sink = (AsciiSinkObject)w;
1745     XRectangle rect;
1746     int width, height;
1747
1748     if (w->core.widget_class != asciiSinkObjectClass)
1749         return;
1750
1751     rect.x = ctx->text.r_margin.left;
1752     rect.y = ctx->text.r_margin.top;
1753     width = (int)XtWidth(ctx) - RHMargins(ctx);
1754     height = (int)XtHeight(ctx) - RVMargins(ctx);
1755     rect.width = width;
1756     rect.height = height;
1757
1758     if (sink->ascii_sink.normgc) {
1759         if (width >= 0 && height >= 0)
1760             XSetClipRectangles(XtDisplay((Widget)ctx), sink->ascii_sink.normgc,
1761                                0, 0, &rect, 1, Unsorted);
1762         else
1763             XSetClipMask(XtDisplay((Widget)ctx), sink->ascii_sink.normgc, None);
1764     }
1765     if (sink->ascii_sink.invgc) {
1766         if (width >= 0 && height >= 0)
1767             XSetClipRectangles(XtDisplay((Widget)ctx), sink->ascii_sink.invgc,
1768                                0, 0, &rect, 1, Unsorted);
1769         else
1770             XSetClipMask(XtDisplay((Widget)ctx), sink->ascii_sink.invgc, None);
1771     }
1772     if (sink->ascii_sink.xorgc) {
1773         if (width >= 0 && height >= 0)
1774             XSetClipRectangles(XtDisplay((Widget)ctx), sink->ascii_sink.xorgc,
1775                                0, 0, &rect, 1, Unsorted);
1776         else
1777             XSetClipMask(XtDisplay((Widget)ctx), sink->ascii_sink.xorgc, None);
1778     }
1779 }
1780
1781 /*
1782  * Function:
1783  *      XawAsciiSinkSetValues
1784  *
1785  * Parameters:
1786  *      current - current state of the object
1787  *      request - what was requested
1788  *      cnew    - what the object will become
1789  *
1790  * Description:
1791  *      Sets the values for the AsciiSink.
1792  *
1793  * Returns:
1794  *      True if redisplay is needed
1795  */
1796 /*ARGSUSED*/
1797 static Boolean
1798 XawAsciiSinkSetValues(Widget current, Widget request, Widget cnew,
1799                       ArgList args, Cardinal *num_args)
1800 {
1801     AsciiSinkObject w = (AsciiSinkObject)cnew;
1802     AsciiSinkObject old_w = (AsciiSinkObject)current;
1803
1804     if (w->ascii_sink.font != old_w->ascii_sink.font
1805         || w->text_sink.background != old_w->text_sink.background
1806         || w->text_sink.foreground != old_w->text_sink.foreground
1807 #ifndef OLDXAW
1808         || w->text_sink.cursor_color != old_w->text_sink.cursor_color
1809         || w->text_sink.properties != old_w->text_sink.properties
1810 #endif
1811         ) {
1812 #ifdef OLDXAW
1813         XtReleaseGC(cnew, w->ascii_sink.normgc);
1814         XtReleaseGC(cnew, w->ascii_sink.invgc);
1815         XtReleaseGC(cnew, w->ascii_sink.xorgc);
1816         GetGC(w);
1817 #endif
1818         ((TextWidget)XtParent(cnew))->text.redisplay_needed = True;
1819     }
1820     else if (w->ascii_sink.echo != old_w->ascii_sink.echo
1821              || w->ascii_sink.display_nonprinting
1822              != old_w->ascii_sink.display_nonprinting)
1823       ((TextWidget)XtParent(cnew))->text.redisplay_needed = True;
1824 #ifndef OLDXAW
1825     if (w->text_sink.properties != old_w->text_sink.properties) {
1826         XawTextProperty *property =
1827             XawTextSinkGetProperty(cnew, XrmStringToQuark("default"));
1828
1829         if (property) {
1830             if (property->mask & XAW_TPROP_FONT)
1831                 w->ascii_sink.font = property->font;
1832             if (property->mask & XAW_TPROP_FOREGROUND)
1833                 w->text_sink.foreground = property->foreground;
1834             if (property->mask & XAW_TPROP_BACKGROUND)
1835                 w->text_sink.background = property->background;
1836         }
1837     }
1838 #endif
1839
1840     return (False);
1841 }
1842
1843 /*
1844  * Function:
1845  *      MaxLines
1846  *
1847  * Parameters:
1848  *      w      - AsciiSink Object
1849  *      height - height to fit lines into
1850  *
1851  * Description:
1852  *      Finds the Maximum number of lines that will fit in a given height.
1853  *
1854  * Returns:
1855  *      The number of lines that will fit
1856  */
1857 /*ARGSUSED*/
1858 static int
1859 MaxLines(Widget w, unsigned int height)
1860 {
1861     AsciiSinkObject sink = (AsciiSinkObject)w;
1862     int font_height;
1863
1864     font_height = sink->ascii_sink.font->ascent + sink->ascii_sink.font->descent + 1;
1865
1866     return ((int)height / font_height);
1867 }
1868
1869 /*
1870  * Function:
1871  *      MaxHeight
1872  *
1873  * Parameters:
1874  *      w     - AsciiSink Object
1875  *      lines - number of lines
1876  *
1877  * Description:
1878  *      Finds the Minium height that will contain a given number lines.
1879  *
1880  * Returns:
1881  *      the height
1882  */
1883 static int
1884 MaxHeight(Widget w, int lines)
1885 {
1886     AsciiSinkObject sink = (AsciiSinkObject)w;
1887
1888     return (lines * (sink->ascii_sink.font->ascent +
1889                      sink->ascii_sink.font->descent + 1));
1890 }
1891
1892 /*
1893  * Function:
1894  *      SetTabs
1895  *
1896  * Parameters:
1897  *      w         - AsciiSink Object
1898  *      tab_count - number of tabs in the list
1899  *      tabs      - text positions of the tabs
1900  *
1901  * Description:
1902  *      Sets the Tab stops.
1903  */
1904 static void
1905 SetTabs(Widget w, int tab_count, short *tabs)
1906 {
1907     AsciiSinkObject sink = (AsciiSinkObject)w;
1908     int i;
1909     Atom XA_FIGURE_WIDTH;
1910     unsigned long figure_width = 0;
1911     XFontStruct *font = sink->ascii_sink.font;
1912
1913     /*
1914      * Find the figure width of the current font
1915      */
1916     XA_FIGURE_WIDTH = XInternAtom(XtDisplayOfObject(w), "FIGURE_WIDTH", False);
1917     if (XA_FIGURE_WIDTH != None
1918         && (!XGetFontProperty(font, XA_FIGURE_WIDTH, &figure_width)
1919             || figure_width == 0)) {
1920         if (font->per_char && font->min_char_or_byte2 <= '$'
1921             && font->max_char_or_byte2 >= '$')
1922             figure_width = font->per_char['$' - font->min_char_or_byte2].width;
1923         else
1924             figure_width = font->max_bounds.width;
1925       }
1926
1927     if (tab_count > sink->text_sink.tab_count) {
1928         sink->text_sink.tabs = (Position *)
1929           XtRealloc((char*)sink->text_sink.tabs, tab_count * sizeof(Position));
1930         sink->text_sink.char_tabs = (short *)
1931           XtRealloc((char*)sink->text_sink.char_tabs, tab_count * sizeof(short));
1932     }
1933
1934     for (i = 0 ; i < tab_count ; i++) {
1935         sink->text_sink.tabs[i] = tabs[i] * figure_width;
1936         sink->text_sink.char_tabs[i] = tabs[i];
1937       }
1938
1939     sink->text_sink.tab_count = tab_count;
1940
1941 #ifndef NO_TAB_FIX
1942     {
1943         TextWidget ctx = (TextWidget)XtParent(w);
1944         ctx->text.redisplay_needed = True;
1945         _XawTextBuildLineTable(ctx, ctx->text.lt.top, True);
1946     }
1947 #endif
1948 }