1/*********************************************************** 2 3Copyright 1987, 1988, 1994, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25 26Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. 27 28 All Rights Reserved 29 30Permission to use, copy, modify, and distribute this software and its 31documentation for any purpose and without fee is hereby granted, 32provided that the above copyright notice appear in all copies and that 33both that copyright notice and this permission notice appear in 34supporting documentation, and that the name of Digital not be 35used in advertising or publicity pertaining to distribution of the 36software without specific, written prior permission. 37 38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 44SOFTWARE. 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 */ 72static void XawAsciiSinkClassPartInitialize(WidgetClass); 73static void XawAsciiSinkInitialize(Widget, Widget, ArgList, Cardinal*); 74static void XawAsciiSinkDestroy(Widget); 75static void XawAsciiSinkResize(Widget); 76static Boolean XawAsciiSinkSetValues(Widget, Widget, Widget, 77 ArgList, Cardinal*); 78static int MaxLines(Widget, unsigned int); 79static int MaxHeight(Widget, int); 80static void SetTabs(Widget, int, short*); 81static void DisplayText(Widget, int, int, 82 XawTextPosition, XawTextPosition, Bool); 83static void InsertCursor(Widget, int, int, XawTextInsertState); 84static void FindPosition(Widget, XawTextPosition, int, int, Bool, 85 XawTextPosition*, int*, int*); 86static void FindDistance(Widget, XawTextPosition, int, XawTextPosition, int*, 87 XawTextPosition*, int*); 88static void Resolve(Widget, XawTextPosition, int, int, XawTextPosition*); 89static void GetCursorBounds(Widget, XRectangle*); 90#ifndef OLDXAW 91static void AsciiPreparePaint(Widget, int, int, 92 XawTextPosition, XawTextPosition, Bool); 93static void AsciiDoPaint(Widget); 94#endif 95 96/* 97 * Prototypes 98 */ 99static void GetGC(AsciiSinkObject); 100static int CharWidth(AsciiSinkObject, XFontStruct*, int, unsigned int); 101static 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 */ 107void _XawTextSinkClearToBackground(Widget, int, int, unsigned, unsigned); 108 109/* 110 * Initialization 111 */ 112#define offset(field) XtOffsetOf(AsciiSinkRec, ascii_sink.field) 113static XtResource resources[] = { 114 { 115 XtNfont, 116 XtCFont, 117 XtRFontStruct, 118 sizeof(XFontStruct*), 119 offset(font), 120 XtRString, 121 (XtPointer)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) 146AsciiSinkClassRec 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 204WidgetClass asciiSinkObjectClass = (WidgetClass)&asciiSinkClassRec; 205 206/* 207 * Implementation 208 */ 209static void 210XawAsciiSinkClassPartInitialize(WidgetClass wc _X_UNUSED) 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 231static int 232CharWidth(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 295static int 296GetTextWidth(TextWidget ctx, int current_width, XFontStruct *font, 297 XawTextPosition from, int length) 298{ 299 int width = 0; 300 301 while (length > 0) { 302 int i; 303 XawTextBlock block; 304 XawTextPosition pos = XawTextSourceRead(ctx->text.source, from, &block, length); 305 306 length = (int)(length - (pos - from)); 307 from = pos; 308 for (i = 0; i < block.length; i++) 309 width += CharWidth((AsciiSinkObject)ctx->text.sink, font, 310 current_width + width, 311 (unsigned char)block.ptr[i]); 312 } 313 314 return (width); 315} 316 317static 318void CalculateBearing(TextWidget ctx, XawTextPosition position, int x, int y, 319 int ascent, int descent, Bool highlight, Bool right) 320{ 321/* 322 * Sample case: 323 * 324 * lbearing| width |rbearing 325 * | | 326 * | #### 327 * | ### | 328 * | #### | 329 * | #### | 330 * | ########## | 331 * | #### | 332 * | #### | 333 * | #### | 334 * | #### | 335 * |### | 336 * #### | 337 * | | 338 * 339 */ 340 AsciiSinkObject sink = (AsciiSinkObject)ctx->text.sink; 341 XawTextAnchor *anchor; 342 XawTextEntity *entity; 343 XawTextProperty *property; 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 = (unsigned char)(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 XawTextPaintStruct *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 = (Boolean)highlight; 386 paint->length = 1; 387 paint->text = XtMalloc(1); 388 paint->text[0] = (char)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 = (unsigned char)(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 XawTextPaintStruct *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 = (Boolean)highlight; 422 paint->length = 1; 423 paint->text = XtMalloc(1); 424 paint->text[0] = (char)c; 425 } 426 } 427 } 428} 429 430static void 431AsciiPreparePaint(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, 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; 446 XawTextBlock block; 447 XFontStruct *font; 448 449 if (!sink->ascii_sink.echo) 450 return; 451 452 /* pass 1: calculate ascent/descent values and x coordinate */ 453 /* XXX the MAX ascent/descent value should be in the line table XXX */ 454 /* XXX the x coordinate can be a parameter, but since it is required 455 to calculate the ascent/descent, do it here to avoid an extra 456 search in the entities */ 457 pos = left = ctx->text.lt.info[line].position; 458 right = ctx->text.lt.info[line + 1].position; 459 right = XawMin(right, ctx->text.lastPos + 1); 460 while (pos < right) { 461 if (XawTextSourceAnchorAndEntity(ctx->text.source, pos, 462 &anchor, &entity)) { 463 if ((property = XawTextSinkGetProperty((Widget)sink, 464 entity->property)) != NULL && 465 (property->mask & XAW_TPROP_FONT)) 466 font = property->font; 467 else 468 font = sink->ascii_sink.font; 469 tmp = pos; 470 pos = anchor->position + entity->offset + entity->length; 471 if ((length = XawMin(from, pos) - tmp) > 0) 472 x += GetTextWidth(ctx, x, font, tmp, (int)length); 473 ascent = XawMax(font->ascent, ascent); 474 descent = XawMax(font->descent, descent); 475 } 476 else if (anchor) { 477 ascent = XawMax(sink->ascii_sink.font->ascent, ascent); 478 descent = XawMax(sink->ascii_sink.font->descent, descent); 479 while (entity && pos < right) { 480 tmp = pos; 481 if ((pos = anchor->position + entity->offset) < tmp) 482 pos = tmp; 483 else { 484 if ((length = XawMin(from, pos) - tmp) > 0) { 485 x += GetTextWidth(ctx, x, sink->ascii_sink.font, tmp, 486 (int)length); 487 tmp += length; 488 } 489 if (pos < right) { 490 pos += entity->length; 491 if ((property = XawTextSinkGetProperty((Widget)sink, 492 entity->property)) != NULL && 493 (property->mask & XAW_TPROP_FONT)) 494 font = property->font; 495 else 496 font = sink->ascii_sink.font; 497 if ((length = XawMin(from, pos) - tmp) > 0) 498 x += GetTextWidth(ctx, x, font, tmp, (int)length); 499 ascent = XawMax(font->ascent, ascent); 500 descent = XawMax(font->descent, descent); 501 } 502 } 503 entity = entity->next; 504 } 505 506 if (anchor->entities == NULL) { 507 tmp = XawMin(pos, from); 508 if ((length = from - tmp) > 0) 509 x += GetTextWidth(ctx, x, sink->ascii_sink.font, tmp, (int)length); 510 break; 511 } 512 } 513 else { 514 tmp = XawMin(pos, from); 515 if ((length = from - tmp) > 0) 516 x += GetTextWidth(ctx, x, sink->ascii_sink.font, tmp, (int)length); 517 ascent = XawMax(sink->ascii_sink.font->ascent, ascent); 518 descent = XawMax(sink->ascii_sink.font->descent, descent); 519 break; 520 } 521 } 522 if (!ascent) 523 ascent = sink->ascii_sink.font->ascent; 524 if (!descent) 525 descent = sink->ascii_sink.font->descent; 526 527 xl = x; 528 529 /* pass 2: feed the XawTextPaintStruct lists */ 530 pos = from; 531 while (pos < to) { 532 int bufsiz; 533 XawTextPaintStruct *paint = XtNew(XawTextPaintStruct); 534 535 paint->next = sink->text_sink.paint->paint; 536 sink->text_sink.paint->paint = paint; 537 paint->x = x; 538 paint->y = y + ascent; 539 paint->property = NULL; 540 paint->max_ascent = ascent; 541 paint->max_descent = descent; 542 paint->backtabs = NULL; 543 paint->highlight = (Boolean)highlight; 544 545 tmp = pos; 546 if (XawTextSourceAnchorAndEntity(ctx->text.source, pos, 547 &anchor, &entity)) { 548 pos = anchor->position + entity->offset + entity->length; 549 if ((paint->property = XawTextSinkGetProperty((Widget)sink, 550 entity->property)) != NULL && 551 (paint->property->mask & XAW_TPROP_FONT)) 552 font = paint->property->font; 553 else 554 font = sink->ascii_sink.font; 555 } 556 else { 557 if (anchor) { 558 while (entity && anchor->position + entity->offset < pos) 559 entity = entity->next; 560 if (entity) 561 pos = anchor->position + entity->offset; 562 else 563 pos = to; 564 } 565 else 566 pos = to; 567 font = sink->ascii_sink.font; 568 } 569 pos = XawMin(pos, to); 570 length = pos - tmp; 571 572 paint->text = XtMalloc((Cardinal)(bufsiz = (int)(pos - tmp + 4))); 573 paint->length = 0; 574 segment.x1 = x; 575 576 while (length > 0) { 577 XawTextPosition pos2 = XawTextSourceRead(ctx->text.source, tmp, &block, (int)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) > (unsigned)bufsiz) 584 paint->text = XtRealloc(paint->text, (Cardinal)(bufsiz += 32)); 585 paint->text[paint->length] = (char)c; 586 if (c == '\n') { 587 x += CharWidth(sink, font, 0, ' '); 588 continue; 589 } 590 if (c == '\t') { 591 x += XTextWidth(font, paint->text, (int)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 = (Boolean)highlight; 646 paint->text = XtMalloc((Cardinal)(bufsiz = (int)(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++] = (char)(((c >> 6) & 7) + '0'); 656 paint->text[paint->length++] = (char)(((c >> 3) & 7) + '0'); 657 paint->text[paint->length] = (char)((c & 7) + '0'); 658 } 659 else { 660 c |= 0100; 661 paint->text[paint->length++] = '^'; 662 paint->text[paint->length] = (char)(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, (int)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 724static int 725qcmp_paint_struct(_Xconst void *left, _Xconst void *right) 726{ 727 return (int)((*(XawTextPaintStruct* _Xconst *)left)->property - 728 (*(XawTextPaintStruct* _Xconst *)right)->property); 729} 730 731static void 732AsciiDoPaint(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 XawTextPaintStruct *paint = list->paint; 740 XawTextProperty *property; 741 XFontStruct *font = NULL; 742 XRectangle *rects; 743 int n_rects, i_rects; 744 GC gc; 745 Bool highlight; 746 XRectangle rect; 747 int width, height, line_width = -1; 748 XGCValues values; 749 750 /* pass 1: clear clipping areas */ 751 /* XXX Don't use XDrawImageString because the font may be italic, and 752 will get incorrectly drawn. Probably, it could be a good idea to 753 check if this is the case, and do special processing. But this 754 will need to be checked if required. */ 755 for (scan = list->clip->scanline; scan && scan->next; scan = scan->next) 756 for (seg = scan->segment; seg; seg = seg->next) 757 _XawTextSinkClearToBackground(ctx->text.sink, 758 seg->x1, scan->y, 759 (unsigned)(seg->x2 - seg->x1), 760 (unsigned)(scan->next->y - scan->y)); 761 762 if (paint && paint->next) { 763 XawTextPaintStruct **paints; 764 int i = 0, n_paints = 0; 765 766 while (paint) { 767 paint = paint->next; 768 ++n_paints; 769 } 770 paints = (XawTextPaintStruct**) 771 XtMalloc((Cardinal)((size_t)n_paints * sizeof(XawTextPaintStruct))); 772 paint = list->paint; 773 while (paint) { 774 paints[i++] = paint; 775 paint = paint->next; 776 } 777 qsort((void*)paints, (size_t)n_paints, sizeof(XawTextPaintStruct*), 778 qcmp_paint_struct); 779 list->paint = paints[0]; 780 for (i = 0; i < n_paints - 1; i++) 781 paints[i]->next = paints[i + 1]; 782 paints[i]->next = NULL; 783 XtFree((XtPointer)paints); 784 } 785 786 /* pass 3: clip gc */ 787 gc = sink->ascii_sink.normgc; 788 789 rect.x = ctx->text.r_margin.left; 790 rect.y = ctx->text.r_margin.top; 791 width = (int)XtWidth(ctx) - RHMargins(ctx); 792 height = (int)XtHeight(ctx) - RVMargins(ctx); 793 rect.width = (unsigned short)width; 794 rect.height = (unsigned short)height; 795 if (width >= 0 && height >= 0) 796 XSetClipRectangles(XtDisplay((Widget)ctx), gc, 797 0, 0, &rect, 1, Unsorted); 798 else 799 XSetClipMask(XtDisplay((Widget)ctx), gc, None); 800 801 /* pass 4: draw backgrounds */ 802 paint = list->paint; 803 property = NULL; 804 rects = NULL; 805 i_rects = n_rects = 0; 806 while (paint) { 807 if (paint->property && (paint->property->mask & XAW_TPROP_BACKGROUND)) { 808 if (property != paint->property) { 809 if (i_rects) 810 XFillRectangles(XtDisplay(ctx), XtWindow(ctx), gc, 811 rects, i_rects); 812 i_rects = 0; 813 property = paint->property; 814 if (property->mask & XAW_TPROP_FONT) 815 font = property->font; 816 else 817 font = sink->ascii_sink.font; 818 XSetForeground(XtDisplay(ctx), gc, property->background); 819 } 820 if (i_rects <= n_rects) 821 rects = (XRectangle*) 822 XtRealloc((XtPointer)rects, (Cardinal)(sizeof(XRectangle) * 823 (size_t)++n_rects)); 824 rects[i_rects].x = (short)paint->x; 825 rects[i_rects].y = (short)(paint->y - font->ascent); 826 rects[i_rects].width = (unsigned short)paint->width; 827 rects[i_rects++].height = (unsigned short)(font->ascent + font->descent); 828 829 if (paint->backtabs) { 830 for (scan = paint->backtabs->scanline; scan && scan->next; 831 scan = scan->next) 832 for (seg = scan->segment; seg; seg = seg->next) { 833 if (i_rects <= n_rects) 834 rects = (XRectangle*) 835 XtRealloc((XtPointer)rects, (Cardinal)(sizeof(XRectangle) * 836 (size_t)++n_rects)); 837 rects[i_rects].x = (short)seg->x1; 838 rects[i_rects].y = (short)scan->y; 839 rects[i_rects].width = (unsigned short)(seg->x2 - seg->x1); 840 rects[i_rects++].height = (unsigned short)(scan->next->y - scan->y); 841 } 842 } 843 844 845 } 846 paint = paint->next; 847 } 848 if (i_rects) 849 XFillRectangles(XtDisplay(ctx), XtWindow(ctx), gc, rects, i_rects); 850 851 paint = list->paint; 852 i_rects = 0; 853 while (paint) { 854 if (paint->highlight) { 855 if (i_rects == 0) 856 XSetForeground(XtDisplay(ctx), gc, sink->text_sink.cursor_color); 857 if (i_rects <= n_rects) 858 rects = (XRectangle*) 859 XtRealloc((XtPointer)rects, (Cardinal)(sizeof(XRectangle) * 860 (size_t)++n_rects)); 861 rects[i_rects].x = (short)paint->x; 862 rects[i_rects].y = (short)(paint->y - paint->max_ascent); 863 rects[i_rects].width = (unsigned short)paint->width; 864 rects[i_rects++].height = (unsigned short)(paint->max_ascent + paint->max_descent + 1); 865 } 866 paint = paint->next; 867 } 868 if (list->hightabs) { 869 for (scan = list->hightabs->scanline; scan && scan->next; 870 scan = scan->next) 871 for (seg = scan->segment; seg; seg = seg->next) { 872 if (i_rects == 0) 873 XSetForeground(XtDisplay(ctx), gc, 874 sink->text_sink.cursor_color); 875 if (i_rects <= n_rects) 876 rects = (XRectangle*) 877 XtRealloc((XtPointer)rects, (Cardinal)(sizeof(XRectangle) * 878 (size_t)++n_rects)); 879 rects[i_rects].x = (short)seg->x1; 880 rects[i_rects].y = (short)scan->y; 881 rects[i_rects].width = (unsigned short)(seg->x2 - seg->x1); 882 rects[i_rects++].height = (unsigned short)(scan->next->y - scan->y); 883 } 884 } 885 886 if (i_rects) 887 XFillRectangles(XtDisplay(ctx), XtWindow(ctx), gc, rects, i_rects); 888 if (rects) 889 XtFree((XtPointer)rects); 890 891 /* pass 5: draw text! */ 892 paint = list->paint; 893 if (paint && (property = paint->property) == NULL) { 894 font = sink->ascii_sink.font; 895 XSetFont(XtDisplay(ctx), gc, font->fid); 896 if (!paint->highlight) 897 XSetForeground(XtDisplay(ctx), gc, sink->text_sink.foreground); 898 } 899 else 900 property = NULL; 901 highlight = False; 902 while (paint) { 903 if (!highlight && paint->highlight) 904 XSetForeground(XtDisplay(ctx), gc, sink->text_sink.background); 905 if (highlight || paint->highlight || paint->property != property) { 906 if (!paint->property || !(paint->property->mask & XAW_TPROP_FONT)) 907 font = sink->ascii_sink.font; 908 else 909 font = paint->property->font; 910 XSetFont(XtDisplay(ctx), gc, font->fid); 911 if (!paint->highlight) { 912 if (!paint->property || 913 !(paint->property->mask & XAW_TPROP_FOREGROUND)) 914 XSetForeground(XtDisplay(ctx), gc, 915 sink->text_sink.foreground); 916 else 917 XSetForeground(XtDisplay(ctx), gc, 918 paint->property->foreground); 919 } 920 highlight = paint->highlight; 921 property = paint->property; 922 } 923 924 if (paint->x < XtWidth(ctx) && paint->x + paint->width > 0) { 925 XDrawString(XtDisplay(ctx), XtWindow(ctx), gc, paint->x, paint->y, 926 paint->text, (int)paint->length); 927 if (property) { 928 if (property->mask & XAW_TPROP_UNDERLINE) { 929 if (line_width != property->underline_thickness) { 930 values.line_width = line_width = 931 property->underline_thickness; 932 XChangeGC(XtDisplay(ctx), gc, GCLineWidth, &values); 933 } 934 935 XDrawLine(XtDisplay(ctx), XtWindow(ctx), gc, paint->x, 936 paint->y + property->underline_position, 937 paint->x + paint->width, 938 paint->y + property->underline_position); 939 } 940 if (property->mask & XAW_TPROP_OVERSTRIKE) { 941 if (line_width != property->underline_thickness) { 942 values.line_width = line_width = 943 property->underline_thickness; 944 XChangeGC(XtDisplay(ctx), gc, GCLineWidth, &values); 945 } 946 947 XDrawLine(XtDisplay(ctx), XtWindow(ctx), gc, paint->x, 948 paint->y - (font->ascent>>1) + (font->descent>>1), 949 paint->x + paint->width, 950 paint->y - (font->ascent>>1) + (font->descent>>1)); 951 } 952 } 953 } 954 955 paint = paint->next; 956 } 957 958 /* pass 6: bearing clipping */ 959 /* dont care on order of drawing or caching of state (by now) */ 960 paint = list->bearings; 961 while (paint) { 962 if (paint->highlight) 963 XSetForeground(XtDisplay(ctx), gc, sink->text_sink.background); 964 if (!paint->property || !(paint->property->mask & XAW_TPROP_FONT)) 965 font = sink->ascii_sink.font; 966 else 967 font = paint->property->font; 968 XSetFont(XtDisplay(ctx), gc, font->fid); 969 if (!paint->highlight) { 970 if (!paint->property || 971 !(paint->property->mask & XAW_TPROP_FOREGROUND)) 972 XSetForeground(XtDisplay(ctx), gc, sink->text_sink.foreground); 973 else 974 XSetForeground(XtDisplay(ctx), gc, paint->property->foreground); 975 } 976 if (paint->x < XtWidth(ctx) && paint->x + paint->width > 0) { 977 XRectangle rect2 = { 978 .x = (short)(paint->x + paint->width), 979 .width = (unsigned short)(XawAbs(paint->width)), /* more than enough */ 980 .y = (short)(paint->y - font->ascent), 981 .height = (unsigned short)((paint->y - font->ascent) + 982 font->ascent + font->descent) 983 }; 984 XSetClipRectangles(XtDisplay((Widget)ctx), gc, 985 0, 0, &rect2, 1, Unsorted); 986 XDrawString(XtDisplay(ctx), XtWindow(ctx), gc, paint->x, paint->y, 987 paint->text, (int)paint->length); 988 } 989 paint = paint->next; 990 } 991} 992#endif 993 994/* 995 * Function: 996 * PaintText 997 * 998 * Parameters: 999 * w - text sink object 1000 * gc - gc to paint text with 1001 * x - location to paint the text 1002 * y - "" 1003 * buf - buffer and length of text to paint. 1004 * len - "" 1005 * clear_bg - clear background before drawing ? 1006 * 1007 * Description: 1008 * Actually paints the text into the window. 1009 * 1010 * Returns: 1011 * the width of the text painted 1012 */ 1013static unsigned int 1014PaintText(Widget w, GC gc, int x, int y, char *buf, int len, Bool clear_bg) 1015{ 1016 AsciiSinkObject sink = (AsciiSinkObject)w; 1017 TextWidget ctx = (TextWidget)XtParent(w); 1018 int width = XTextWidth(sink->ascii_sink.font, buf, len); 1019 1020 if ((x > XtWidth(ctx)) || width <= -x) /* Don't draw if we can't see it */ 1021 return (unsigned)(width); 1022 1023 if (clear_bg) { 1024 _XawTextSinkClearToBackground(w, x, y - sink->ascii_sink.font->ascent, 1025 (unsigned)width, 1026 (unsigned)(sink->ascii_sink.font->ascent 1027 + sink->ascii_sink.font->descent)); 1028 XDrawString(XtDisplay(ctx), XtWindow(ctx), gc, x, y, buf, len); 1029 } 1030 else 1031 XDrawImageString(XtDisplay(ctx), XtWindow(ctx), gc, x, y, buf, len); 1032 1033 return (unsigned)(width); 1034} 1035 1036static void 1037DisplayText(Widget w, int x, int y, 1038 XawTextPosition pos1, XawTextPosition pos2, Bool highlight) 1039{ 1040 TextWidget ctx = (TextWidget)XtParent(w); 1041 AsciiSinkObject sink = (AsciiSinkObject)w; 1042 XFontStruct *font = sink->ascii_sink.font; 1043 Widget source = XawTextGetSource(XtParent(w)); 1044 unsigned char buf[260]; 1045 int j, k; 1046 XawTextBlock blk; 1047 GC gc, invgc, tabgc; 1048 int max_x; 1049 Bool clear_bg; 1050 1051 if (!sink->ascii_sink.echo || !ctx->text.lt.lines) 1052 return; 1053 1054 max_x = (int)XtWidth(ctx) - ctx->text.r_margin.right; 1055 clear_bg = !highlight && ctx->core.background_pixmap != XtUnspecifiedPixmap; 1056 1057 gc = highlight ? sink->ascii_sink.invgc : sink->ascii_sink.normgc; 1058 invgc = highlight ? sink->ascii_sink.normgc : sink->ascii_sink.invgc; 1059 1060 if (highlight && sink->ascii_sink.xorgc) 1061 tabgc = sink->ascii_sink.xorgc; 1062 else 1063 tabgc = invgc; 1064 1065 y += sink->ascii_sink.font->ascent; 1066 for (j = 0; pos1 < pos2;) { 1067 pos1 = XawTextSourceRead(source, pos1, &blk, (int)(pos2 - pos1)); 1068 for (k = 0; k < blk.length; k++) { 1069 if ((unsigned)j >= sizeof(buf) - 4) { /* buffer full, dump the text */ 1070 if ((x = (int)((unsigned)x + PaintText(w, gc, x, y, (char*)buf, j, clear_bg))) 1071 >= max_x) 1072 return; 1073 j = 0; 1074 } 1075 buf[j] = (unsigned char)blk.ptr[k]; 1076 if (buf[j] == XawLF) /* line feeds ('\n') are not printed */ 1077 continue; 1078 1079 else if (buf[j] == '\t') { 1080 int width; 1081 1082 if (j != 0 1083 && (x = (int)((unsigned)x + PaintText(w, gc, x, y, (char*)buf, j, clear_bg))) 1084 >= max_x) 1085 return; 1086 1087 if ((width = CharWidth(sink, font, x, '\t')) > -x) { 1088 if (clear_bg) 1089 _XawTextSinkClearToBackground(w, x, y-font->ascent, (unsigned)width, 1090 (unsigned)(font->ascent+font->descent)); 1091 else 1092 XFillRectangle(XtDisplayOfObject(w), XtWindowOfObject(w), 1093 tabgc, x, y - font->ascent, (unsigned)width, 1094 (unsigned)(font->ascent + font->descent)); 1095 } 1096 1097 if ((x += width) >= max_x) 1098 return; 1099 1100 j = -1; 1101 } 1102 else if ((buf[j] & 0177) < XawSP || buf[j] == 0177) { 1103 if (sink->ascii_sink.display_nonprinting) { 1104 unsigned char c = buf[j]; 1105 1106 if (c > 0177) { 1107 buf[j++] = '\\'; 1108 buf[j++] = (unsigned char)(((c >> 6) & 7) + '0'); 1109 buf[j++] = (unsigned char)(((c >> 3) & 7) + '0'); 1110 buf[j] = (unsigned char)((c & 7) + '0'); 1111 } 1112 else { 1113 c |= 0100; 1114 buf[j++] = '^'; 1115 buf[j] = c == 0177 ? '?' : c; 1116 } 1117 } 1118 else 1119 buf[j] = ' '; 1120 } 1121 j++; 1122 } 1123 } 1124 1125 if (j > 0) 1126 (void)PaintText(w, gc, x, y, (char*)buf, j, clear_bg); 1127} 1128 1129/* 1130 * Function: 1131 * GetCursorBounds 1132 * 1133 * Parameters: 1134 * w - text sink object 1135 * rect - X rectangle to return the cursor bounds 1136 * 1137 * Description: 1138 * Returns the size and location of the cursor. 1139 */ 1140static void 1141GetCursorBounds(Widget w, XRectangle *rect) 1142{ 1143 AsciiSinkObject sink = (AsciiSinkObject)w; 1144 XFontStruct *font = sink->ascii_sink.font; 1145 unsigned char ch; 1146#ifndef OLDXAW 1147 TextWidget ctx = (TextWidget)XtParent(w); 1148 XawTextBlock block; 1149 XawTextAnchor *anchor; 1150 XawTextEntity *entity; 1151 XawTextProperty *property; 1152 1153 if (XawTextSourceAnchorAndEntity(XawTextGetSource(XtParent(w)), 1154 sink->ascii_sink.cursor_position, 1155 &anchor, &entity)) { 1156 if ((property = XawTextSinkGetProperty((Widget)sink, 1157 entity->property)) != NULL && 1158 (property->mask & XAW_TPROP_FONT)) 1159 font = property->font; 1160 } 1161 (void)XawTextSourceRead(XawTextGetSource((Widget)ctx), 1162 ctx->text.insertPos, &block, 1); 1163 if (!block.length || block.ptr[0] == '\n' || block.ptr[0] == '\t') 1164 ch = ' '; 1165 else if ((*((unsigned char*)block.ptr) & 0177) < XawSP || 1166 *(unsigned char*)block.ptr == 0177) { 1167 if (sink->ascii_sink.display_nonprinting) 1168 ch = *((unsigned char*)block.ptr) > 0177 ? '\\' : '^'; 1169 else 1170 ch = ' '; 1171 } 1172 else 1173 ch = *(unsigned char*)block.ptr; 1174#else 1175 ch = ' '; 1176#endif 1177 1178 rect->width = (unsigned short)(CharWidth(sink, font, 0, ch)); 1179 rect->height = (unsigned short)(font->descent + font->ascent + 1); 1180 1181 rect->x = sink->ascii_sink.cursor_x; 1182 rect->y = (short)(sink->ascii_sink.cursor_y - font->ascent); 1183} 1184 1185/* this function is required to support different fonts and correctly place 1186 * the cursor. There are better ways to calculate the base line, but there is 1187 * no place/code (yet) to store this information. 1188 */ 1189static int 1190FindCursorY(TextWidget ctx, XawTextPosition position) 1191{ 1192 int y, line, ascent; 1193 AsciiSinkObject sink = (AsciiSinkObject)ctx->text.sink; 1194#ifndef OLDXAW 1195 XawTextAnchor *anchor; 1196 XawTextEntity *entity; 1197 XawTextProperty *property; 1198 XawTextPosition left, right; 1199#endif 1200 1201 for (line = 0; line < ctx->text.lt.lines; line++) 1202 if (position < ctx->text.lt.info[line + 1].position) 1203 break; 1204 1205 y = ctx->text.lt.info[line].y; 1206#ifndef OLDXAW 1207 ascent = 0; 1208 left = ctx->text.lt.info[line].position; 1209 right = ctx->text.lt.info[line + 1].position; 1210 right = XawMin(right, ctx->text.lastPos + 1); 1211 while (left < right) { 1212 if (XawTextSourceAnchorAndEntity(ctx->text.source, left, 1213 &anchor, &entity)) { 1214 if ((property = XawTextSinkGetProperty((Widget)sink, 1215 entity->property)) != NULL && 1216 (property->mask & XAW_TPROP_FONT)) 1217 ascent = XawMax(property->font->ascent, ascent); 1218 else 1219 ascent = XawMax(sink->ascii_sink.font->ascent, ascent); 1220 left = anchor->position + entity->offset + entity->length; 1221 } 1222 else if (anchor) { 1223 ascent = XawMax(sink->ascii_sink.font->ascent, ascent); 1224 while (entity) { 1225 XawTextPosition tmp = anchor->position + entity->offset + entity->length; 1226 1227 if (tmp > left && tmp < right) { 1228 left = tmp; 1229 if ((property = XawTextSinkGetProperty((Widget)sink, 1230 entity->property)) != NULL && 1231 (property->mask & XAW_TPROP_FONT)) 1232 ascent = XawMax(property->font->ascent, ascent); 1233 else 1234 ascent = XawMax(sink->ascii_sink.font->ascent, ascent); 1235 } 1236 entity = entity->next; 1237 } 1238 if (entity == NULL) 1239 break; 1240 } 1241 else { 1242 ascent = XawMax(sink->ascii_sink.font->ascent, ascent); 1243 break; 1244 } 1245 } 1246 if (!ascent) 1247 ascent = sink->ascii_sink.font->ascent; 1248#else 1249 ascent = sink->ascii_sink.font->ascent; 1250#endif 1251 1252 return (y + ascent); 1253} 1254 1255static void 1256InsertCursor(Widget w, int x, int y, XawTextInsertState state) 1257{ 1258 AsciiSinkObject sink = (AsciiSinkObject)w; 1259 XFontStruct *font = sink->ascii_sink.font; 1260 TextWidget ctx = (TextWidget)XtParent(w); 1261 XawTextPosition position = XawTextGetInsertionPoint((Widget)ctx); 1262 Boolean overflow = ((unsigned)x & 0xffff8000) != 0; 1263#ifndef OLDXAW 1264 XawTextAnchor *anchor; 1265 XawTextEntity *entity; 1266 XawTextProperty *property; 1267#endif 1268 1269 if (XtIsRealized((Widget)ctx)) { 1270 int fheight; 1271 XawTextBlock block; 1272 XawTextPosition selection_start, selection_end; 1273 Boolean has_selection; 1274 1275 if (!sink->ascii_sink.echo) { 1276 if (sink->ascii_sink.laststate != state) { 1277 int width = CharWidth(sink, font, 0, ' ') - 1; 1278 1279 x = ctx->text.margin.left; 1280 y = ctx->text.margin.top; 1281 font = sink->ascii_sink.font; 1282 fheight = font->ascent + font->descent; 1283 if (state == XawisOn) { 1284 if (ctx->text.hasfocus) 1285 XFillRectangle(XtDisplay(ctx), XtWindow(ctx), 1286 sink->ascii_sink.xorgc, x, y, 1287 (unsigned)(width + 1), (unsigned)(fheight + 1)); 1288 else 1289 XDrawRectangle(XtDisplay(ctx), XtWindow(ctx), 1290 sink->ascii_sink.xorgc, x, y, 1291 (unsigned)width, (unsigned)fheight); 1292 1293 } 1294 else 1295 _XawTextSinkClearToBackground(w, x, y, 1296 (unsigned)(width + 1), (unsigned)(fheight + 1)); 1297 } 1298 sink->ascii_sink.cursor_x = (short)x; 1299 sink->ascii_sink.cursor_y = (short)y; 1300 sink->ascii_sink.laststate = state; 1301 return; 1302 } 1303 1304 1305 XawTextGetSelectionPos((Widget)ctx, &selection_start, &selection_end); 1306 has_selection = selection_start != selection_end; 1307 1308 if (sink->ascii_sink.laststate != state) { 1309 unsigned char ch; 1310 1311#ifndef OLDXAW 1312 if (XawTextSourceAnchorAndEntity(ctx->text.source, 1313 position, &anchor, &entity) && 1314 (property = XawTextSinkGetProperty((Widget)sink, 1315 entity->property)) != NULL && 1316 (property->mask & XAW_TPROP_FONT)) 1317 font = property->font; 1318 else 1319 font = sink->ascii_sink.font; 1320#endif 1321 1322 fheight = font->ascent + font->descent; 1323 (void)XawTextSourceRead(XawTextGetSource((Widget)ctx), 1324 position, &block, 1); 1325 if (!block.length || block.ptr[0] == '\n' || block.ptr[0] == '\t') 1326 ch = ' '; 1327 else if ((*((unsigned char*)block.ptr) & 0177) < XawSP 1328 || *(unsigned char*)block.ptr == 0177) { 1329 if (sink->ascii_sink.display_nonprinting) 1330 ch = *((unsigned char*)block.ptr) > 0177 ? '\\' : '^'; 1331 else 1332 ch = ' '; 1333 } 1334 else 1335 ch = *(unsigned char*)block.ptr; 1336 1337 y = FindCursorY(ctx, position); 1338 if (ctx->text.hasfocus && !has_selection) 1339 XFillRectangle(XtDisplay(ctx), XtWindow(ctx), 1340 sink->ascii_sink.xorgc, x, y - font->ascent, 1341 (unsigned)CharWidth(sink, font, 0, ch), 1342 (unsigned)(fheight + 1)); 1343 else 1344 XDrawRectangle(XtDisplay(ctx), XtWindow(ctx), 1345 sink->ascii_sink.xorgc, x, y - font->ascent, 1346 (unsigned)(CharWidth(sink, font, 0, ch) - 1), 1347 (unsigned)fheight); 1348 } 1349 } 1350 1351 sink->ascii_sink.cursor_x = (short)(overflow ? -16384 : x); 1352 sink->ascii_sink.cursor_y = (short)y; 1353 sink->ascii_sink.laststate = state; 1354 sink->ascii_sink.cursor_position = position; 1355} 1356 1357/* 1358 * Given two positions, find the distance between them 1359 */ 1360static void 1361FindDistance(Widget w, XawTextPosition fromPos, int fromx, 1362 XawTextPosition toPos, int *resWidth, 1363 XawTextPosition *resPos, int *resHeight) 1364{ 1365#ifndef OLDXAW 1366 AsciiSinkObject sink = (AsciiSinkObject)w; 1367 TextWidget ctx = (TextWidget)XtParent(w); 1368 XFontStruct *font; 1369 Widget source = ctx->text.source; 1370 XawTextPosition idx, pos; 1371 unsigned char c; 1372 XawTextBlock blk; 1373 int i, rWidth, ascent = 0, descent = 0; 1374 XawTextAnchor *anchor; 1375 XawTextEntity *entity; 1376 XawTextProperty *property; 1377 Cardinal length; 1378 Bool done = False; 1379 1380 pos = idx = fromPos; 1381 rWidth = 0; 1382 1383 while (!done) { 1384 if (XawTextSourceAnchorAndEntity(source, pos, &anchor, &entity)) { 1385 length = (Cardinal)(anchor->position + entity->offset + entity->length); 1386 length = (Cardinal)(XawMin(toPos, length) - pos); 1387 if ((property = XawTextSinkGetProperty((Widget)sink, 1388 entity->property)) != NULL && 1389 (property->mask & XAW_TPROP_FONT)) 1390 font = property->font; 1391 else 1392 font = sink->ascii_sink.font; 1393 } 1394 else { 1395 if (anchor) { 1396 while (entity && anchor->position + entity->offset < pos) 1397 entity = entity->next; 1398 if (entity) { 1399 length = (Cardinal)(anchor->position + entity->offset); 1400 length = (Cardinal)(XawMin(toPos, length) - pos); 1401 } 1402 else 1403 length = (Cardinal)(XawMin(toPos - pos, 4096)); 1404 } 1405 else 1406 length = (Cardinal)(XawMin(toPos - pos, 4096)); 1407 font = sink->ascii_sink.font; 1408 } 1409 1410 ascent = XawMax(font->ascent, ascent); 1411 descent = XawMax(font->descent, descent); 1412 1413 pos = XawTextSourceRead(source, pos, &blk, (int)length); 1414 if (blk.length == 0 && pos == idx) /* eof reached */ 1415 break; 1416 1417 idx = blk.firstPos; 1418 for (i = 0; idx < toPos; i++, idx++) { 1419 if (i >= blk.length) 1420 break; 1421 c = (unsigned char)blk.ptr[i]; 1422 rWidth += CharWidth(sink, font, fromx + rWidth, c); 1423 if (c == XawLF) { 1424 idx++; 1425 done = True; 1426 break; 1427 } 1428 } 1429 if (idx >= toPos) 1430 break; 1431 } 1432 1433 *resPos = idx; 1434 *resWidth = rWidth; 1435 *resHeight = ascent + descent + 1; 1436#else 1437 AsciiSinkObject sink = (AsciiSinkObject)w; 1438 TextWidget ctx = (TextWidget)XtParent(w); 1439 XFontStruct *font = sink->ascii_sink.font; 1440 Widget source = ctx->text.source; 1441 XawTextPosition idx, pos; 1442 XawTextBlock blk; 1443 int i, rWidth; 1444 1445 pos = XawTextSourceRead(source, fromPos, &blk, (int)(toPos - fromPos)); 1446 rWidth = 0; 1447 for (i = 0, idx = fromPos; idx < toPos; i++, idx++) { 1448 unsigned char c; 1449 1450 if (i >= blk.length) { 1451 i = 0; 1452 pos = XawTextSourceRead(source, pos, &blk, (int)(toPos - pos)); 1453 if (blk.length == 0) 1454 break; 1455 } 1456 c = (unsigned char)blk.ptr[i]; 1457 rWidth += CharWidth(sink, font, fromx + rWidth, c); 1458 if (c == XawLF) { 1459 idx++; 1460 break; 1461 } 1462 } 1463 1464 *resPos = idx; 1465 *resWidth = rWidth; 1466 *resHeight = font->ascent + font->descent + 1; 1467#endif 1468} 1469 1470static void 1471FindPosition(Widget w, XawTextPosition fromPos, int fromx, int width, 1472 Bool stopAtWordBreak, XawTextPosition *resPos, 1473 int *resWidth, int *resHeight) 1474{ 1475#ifndef OLDXAW 1476 AsciiSinkObject sink = (AsciiSinkObject)w; 1477 TextWidget ctx = (TextWidget)XtParent(w); 1478 Widget source = ctx->text.source; 1479 XFontStruct *font; 1480 XawTextPosition idx, pos, whiteSpacePosition = 0; 1481 int i, lastWidth, whiteSpaceWidth, rWidth, ascent = 0, descent = 0; 1482 Boolean whiteSpaceSeen; 1483 unsigned char c; 1484 XawTextBlock blk; 1485 XawTextAnchor *anchor; 1486 XawTextEntity *entity; 1487 XawTextProperty *property; 1488 Cardinal length; 1489 Bool done = False; 1490 1491 pos = idx = fromPos; 1492 rWidth = lastWidth = whiteSpaceWidth = 0; 1493 whiteSpaceSeen = False; 1494 c = 0; 1495 1496 while (!done) { 1497 font = sink->ascii_sink.font; 1498 if (XawTextSourceAnchorAndEntity(source, pos, &anchor, &entity)) { 1499 length = (Cardinal)(anchor->position + entity->offset + entity->length - pos); 1500 if ((property = XawTextSinkGetProperty((Widget)sink, 1501 entity->property)) != NULL && 1502 (property->mask & XAW_TPROP_FONT)) 1503 font = property->font; 1504 } 1505 else { 1506 if (anchor) { 1507 while (entity && anchor->position + entity->offset < pos) 1508 entity = entity->next; 1509 if (entity) 1510 length = (Cardinal)(anchor->position + entity->offset - pos); 1511 else 1512 length = 4096; 1513 } 1514 else 1515 length = 4096; 1516 } 1517 1518 ascent = XawMax(font->ascent, ascent); 1519 descent = XawMax(font->descent, descent); 1520 1521 pos = XawTextSourceRead(source, pos, &blk, (int)length); 1522 if (blk.length == 0 && pos == idx) /* eof reached */ 1523 break; 1524 1525 idx = blk.firstPos; 1526 for (i = 0; rWidth <= width && i < blk.length; i++, idx++) { 1527 c = (unsigned char)blk.ptr[i]; 1528 lastWidth = rWidth; 1529 rWidth += CharWidth(sink, font, fromx + rWidth, c); 1530 1531 if (c == XawLF) { 1532 idx++; 1533 done = True; 1534 break; 1535 } 1536 else if ((c == XawSP || c == XawTAB) && rWidth <= width) { 1537 whiteSpaceSeen = True; 1538 whiteSpacePosition = idx; 1539 whiteSpaceWidth = rWidth; 1540 } 1541 } 1542 if (rWidth > width) 1543 break; 1544 } 1545 1546 if (rWidth > width && idx > fromPos) { 1547 idx--; 1548 rWidth = lastWidth; 1549 if (stopAtWordBreak && whiteSpaceSeen) { 1550 idx = whiteSpacePosition + 1; 1551 rWidth = whiteSpaceWidth; 1552 } 1553 } 1554 1555 if (idx >= ctx->text.lastPos && c != XawLF) 1556 idx = ctx->text.lastPos + 1; 1557 1558 *resPos = idx; 1559 *resWidth = rWidth; 1560 *resHeight = ascent + descent + 1; 1561#else 1562 AsciiSinkObject sink = (AsciiSinkObject)w; 1563 TextWidget ctx = (TextWidget)XtParent(w); 1564 Widget source = ctx->text.source; 1565 XFontStruct *font = sink->ascii_sink.font; 1566 XawTextPosition idx, pos, whiteSpacePosition = 0; 1567 int i, lastWidth, whiteSpaceWidth, rWidth; 1568 Boolean whiteSpaceSeen; 1569 unsigned char c; 1570 XawTextBlock blk; 1571 1572 pos = XawTextSourceRead(source, fromPos, &blk, BUFSIZ); 1573 rWidth = lastWidth = whiteSpaceWidth = 0; 1574 whiteSpaceSeen = False; 1575 c = 0; 1576 1577 for (i = 0, idx = fromPos; rWidth <= width; i++, idx++) { 1578 if (i >= blk.length) { 1579 i = 0; 1580 pos = XawTextSourceRead(source, pos, &blk, BUFSIZ); 1581 if (blk.length == 0) 1582 break; 1583 } 1584 c = (unsigned char)blk.ptr[i]; 1585 lastWidth = rWidth; 1586 rWidth += CharWidth(sink, font, fromx + rWidth, c); 1587 1588 if (c == XawLF) { 1589 idx++; 1590 break; 1591 } 1592 else if ((c == XawSP || c == XawTAB) && rWidth <= width) { 1593 whiteSpaceSeen = True; 1594 whiteSpacePosition = idx; 1595 whiteSpaceWidth = rWidth; 1596 } 1597 } 1598 1599 if (rWidth > width && idx > fromPos) { 1600 idx--; 1601 rWidth = lastWidth; 1602 if (stopAtWordBreak && whiteSpaceSeen) { 1603 idx = whiteSpacePosition + 1; 1604 rWidth = whiteSpaceWidth; 1605 } 1606 } 1607 1608 if (idx >= ctx->text.lastPos && c != XawLF) 1609 idx = ctx->text.lastPos + 1; 1610 1611 *resPos = idx; 1612 *resWidth = rWidth; 1613 *resHeight = font->ascent + font->descent + 1; 1614#endif 1615} 1616 1617static void 1618Resolve(Widget w, XawTextPosition pos, int fromx, int width, 1619 XawTextPosition *pos_return) 1620{ 1621 int resWidth, resHeight; 1622 Widget source = XawTextGetSource(XtParent(w)); 1623 1624 FindPosition(w, pos, fromx, width, False, pos_return, &resWidth, &resHeight); 1625 if (*pos_return > GETLASTPOS) 1626 *pos_return = GETLASTPOS; 1627} 1628 1629static void 1630GetGC(AsciiSinkObject sink) 1631{ 1632 XtGCMask valuemask = (GCFont | GCGraphicsExposures | GCClipXOrigin | 1633 GCForeground | GCBackground); 1634 XGCValues values = { 1635 /* XXX We dont want to share a gc that will change the clip-mask */ 1636 .clip_x_origin = (int)(long)sink, 1637 .clip_mask = None, 1638 .font = sink->ascii_sink.font->fid, 1639 .graphics_exposures = False, 1640 1641 .foreground = sink->text_sink.foreground, 1642 .background = sink->text_sink.background 1643 }; 1644 sink->ascii_sink.normgc = XtAllocateGC((Widget)sink, 0, valuemask, &values, 1645 GCClipMask | GCFont | GCForeground | 1646 GCBackground, 0); 1647 1648 values.foreground = sink->text_sink.background; 1649#ifndef OLDXAW 1650 values.background = sink->text_sink.cursor_color; 1651#else 1652 values.background = sink->text_sink.foreground; 1653#endif 1654 sink->ascii_sink.invgc = XtAllocateGC((Widget)sink, 0, valuemask, &values, 1655 GCClipMask | GCFont, 0); 1656 1657 valuemask |= GCFunction; 1658 values.function = GXxor; 1659#ifndef OLDXAW 1660 values.foreground = sink->text_sink.background ^ sink->text_sink.cursor_color; 1661#else 1662 values.foreground = sink->text_sink.background ^ sink->text_sink.foreground; 1663#endif 1664 values.background = 0L; 1665 sink->ascii_sink.xorgc = XtAllocateGC((Widget)sink, 0, valuemask, 1666 &values, GCClipMask | GCFont, 0); 1667 1668 XawAsciiSinkResize((Widget)sink); 1669} 1670 1671/* Function: 1672 * XawAsciiSinkInitialize 1673 * 1674 * Parameters: 1675 * request - the requested and new values for the object instance 1676 * cnew - "" 1677 * 1678 * Description: 1679 * Initializes the TextSink Object. 1680 */ 1681/*ARGSUSED*/ 1682static void 1683XawAsciiSinkInitialize(Widget request _X_UNUSED, Widget cnew, 1684 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 1685{ 1686 AsciiSinkObject sink = (AsciiSinkObject)cnew; 1687 1688 if (!sink->ascii_sink.font) XtError("Aborting: no font found\n"); 1689 1690 GetGC(sink); 1691 1692 sink->ascii_sink.cursor_position = 0; 1693 sink->ascii_sink.laststate = XawisOff; 1694 sink->ascii_sink.cursor_x = sink->ascii_sink.cursor_y = 0; 1695} 1696 1697/* 1698 * Function: 1699 * XawAsciiSinkDestroy 1700 * 1701 * Parameters: 1702 * w - AsciiSink Object 1703 * 1704 * Description: 1705 * This function cleans up when the object is destroyed. 1706 */ 1707static void 1708XawAsciiSinkDestroy(Widget w) 1709{ 1710 AsciiSinkObject sink = (AsciiSinkObject)w; 1711 1712 XtReleaseGC(w, sink->ascii_sink.normgc); 1713 XtReleaseGC(w, sink->ascii_sink.invgc); 1714 XtReleaseGC(w, sink->ascii_sink.xorgc); 1715 1716 sink->ascii_sink.normgc = 1717 sink->ascii_sink.invgc = 1718 sink->ascii_sink.xorgc = NULL; 1719} 1720 1721static void 1722XawAsciiSinkResize(Widget w) 1723{ 1724 TextWidget ctx = (TextWidget)XtParent(w); 1725 AsciiSinkObject sink = (AsciiSinkObject)w; 1726 XRectangle rect; 1727 int width, height; 1728 1729 if (w->core.widget_class != asciiSinkObjectClass) 1730 return; 1731 1732 rect.x = ctx->text.r_margin.left; 1733 rect.y = ctx->text.r_margin.top; 1734 width = (int)XtWidth(ctx) - RHMargins(ctx); 1735 height = (int)XtHeight(ctx) - RVMargins(ctx); 1736 rect.width = (unsigned short)width; 1737 rect.height = (unsigned short)height; 1738 1739 if (sink->ascii_sink.normgc) { 1740 if (width >= 0 && height >= 0) 1741 XSetClipRectangles(XtDisplay((Widget)ctx), sink->ascii_sink.normgc, 1742 0, 0, &rect, 1, Unsorted); 1743 else 1744 XSetClipMask(XtDisplay((Widget)ctx), sink->ascii_sink.normgc, None); 1745 } 1746 if (sink->ascii_sink.invgc) { 1747 if (width >= 0 && height >= 0) 1748 XSetClipRectangles(XtDisplay((Widget)ctx), sink->ascii_sink.invgc, 1749 0, 0, &rect, 1, Unsorted); 1750 else 1751 XSetClipMask(XtDisplay((Widget)ctx), sink->ascii_sink.invgc, None); 1752 } 1753 if (sink->ascii_sink.xorgc) { 1754 if (width >= 0 && height >= 0) 1755 XSetClipRectangles(XtDisplay((Widget)ctx), sink->ascii_sink.xorgc, 1756 0, 0, &rect, 1, Unsorted); 1757 else 1758 XSetClipMask(XtDisplay((Widget)ctx), sink->ascii_sink.xorgc, None); 1759 } 1760} 1761 1762/* 1763 * Function: 1764 * XawAsciiSinkSetValues 1765 * 1766 * Parameters: 1767 * current - current state of the object 1768 * request - what was requested 1769 * cnew - what the object will become 1770 * 1771 * Description: 1772 * Sets the values for the AsciiSink. 1773 * 1774 * Returns: 1775 * True if redisplay is needed 1776 */ 1777/*ARGSUSED*/ 1778static Boolean 1779XawAsciiSinkSetValues(Widget current, Widget request _X_UNUSED, Widget cnew, 1780 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 1781{ 1782 AsciiSinkObject w = (AsciiSinkObject)cnew; 1783 AsciiSinkObject old_w = (AsciiSinkObject)current; 1784 1785 if (w->ascii_sink.font != old_w->ascii_sink.font 1786 || w->text_sink.background != old_w->text_sink.background 1787 || w->text_sink.foreground != old_w->text_sink.foreground 1788#ifndef OLDXAW 1789 || w->text_sink.cursor_color != old_w->text_sink.cursor_color 1790 || w->text_sink.properties != old_w->text_sink.properties 1791#endif 1792 ) { 1793#ifdef OLDXAW 1794 XtReleaseGC(cnew, w->ascii_sink.normgc); 1795 XtReleaseGC(cnew, w->ascii_sink.invgc); 1796 XtReleaseGC(cnew, w->ascii_sink.xorgc); 1797 GetGC(w); 1798#endif 1799 ((TextWidget)XtParent(cnew))->text.redisplay_needed = True; 1800 } 1801 else if (w->ascii_sink.echo != old_w->ascii_sink.echo 1802 || w->ascii_sink.display_nonprinting 1803 != old_w->ascii_sink.display_nonprinting) 1804 ((TextWidget)XtParent(cnew))->text.redisplay_needed = True; 1805#ifndef OLDXAW 1806 if (w->text_sink.properties != old_w->text_sink.properties) { 1807 XawTextProperty *property = 1808 XawTextSinkGetProperty(cnew, XrmStringToQuark("default")); 1809 1810 if (property) { 1811 if (property->mask & XAW_TPROP_FONT) 1812 w->ascii_sink.font = property->font; 1813 if (property->mask & XAW_TPROP_FOREGROUND) 1814 w->text_sink.foreground = property->foreground; 1815 if (property->mask & XAW_TPROP_BACKGROUND) 1816 w->text_sink.background = property->background; 1817 } 1818 } 1819#endif 1820 1821 return (False); 1822} 1823 1824/* 1825 * Function: 1826 * MaxLines 1827 * 1828 * Parameters: 1829 * w - AsciiSink Object 1830 * height - height to fit lines into 1831 * 1832 * Description: 1833 * Finds the Maximum number of lines that will fit in a given height. 1834 * 1835 * Returns: 1836 * The number of lines that will fit 1837 */ 1838/*ARGSUSED*/ 1839static int 1840MaxLines(Widget w, unsigned int height) 1841{ 1842 AsciiSinkObject sink = (AsciiSinkObject)w; 1843 int font_height; 1844 1845 font_height = sink->ascii_sink.font->ascent + sink->ascii_sink.font->descent + 1; 1846 1847 return ((int)height / font_height); 1848} 1849 1850/* 1851 * Function: 1852 * MaxHeight 1853 * 1854 * Parameters: 1855 * w - AsciiSink Object 1856 * lines - number of lines 1857 * 1858 * Description: 1859 * Finds the Minimum height that will contain a given number lines. 1860 * 1861 * Returns: 1862 * the height 1863 */ 1864static int 1865MaxHeight(Widget w, int lines) 1866{ 1867 AsciiSinkObject sink = (AsciiSinkObject)w; 1868 1869 return (lines * (sink->ascii_sink.font->ascent + 1870 sink->ascii_sink.font->descent + 1)); 1871} 1872 1873/* 1874 * Function: 1875 * SetTabs 1876 * 1877 * Parameters: 1878 * w - AsciiSink Object 1879 * tab_count - number of tabs in the list 1880 * tabs - text positions of the tabs 1881 * 1882 * Description: 1883 * Sets the Tab stops. 1884 */ 1885static void 1886SetTabs(Widget w, int tab_count, short *tabs) 1887{ 1888 AsciiSinkObject sink = (AsciiSinkObject)w; 1889 int i; 1890 Atom XA_FIGURE_WIDTH; 1891 unsigned long figure_width = 0; 1892 XFontStruct *font = sink->ascii_sink.font; 1893 1894 /* 1895 * Find the figure width of the current font 1896 */ 1897 XA_FIGURE_WIDTH = XInternAtom(XtDisplayOfObject(w), "FIGURE_WIDTH", False); 1898 if (XA_FIGURE_WIDTH != None 1899 && (!XGetFontProperty(font, XA_FIGURE_WIDTH, &figure_width) 1900 || figure_width == 0)) { 1901 if (font->per_char && font->min_char_or_byte2 <= '$' 1902 && font->max_char_or_byte2 >= '$') 1903 figure_width = (unsigned long)font->per_char['$' - font->min_char_or_byte2].width; 1904 else 1905 figure_width = (unsigned long)font->max_bounds.width; 1906 } 1907 1908 if (tab_count > sink->text_sink.tab_count) { 1909 sink->text_sink.tabs = (Position *) 1910 XtRealloc((char*)sink->text_sink.tabs, (Cardinal)((size_t)tab_count * sizeof(Position))); 1911 sink->text_sink.char_tabs = (short *) 1912 XtRealloc((char*)sink->text_sink.char_tabs, (Cardinal)((size_t)tab_count * sizeof(short))); 1913 } 1914 1915 for (i = 0 ; i < tab_count ; i++) { 1916 sink->text_sink.tabs[i] = (Position)((size_t)tabs[i] * figure_width); 1917 sink->text_sink.char_tabs[i] = tabs[i]; 1918 } 1919 1920 sink->text_sink.tab_count = tab_count; 1921 1922#ifndef NO_TAB_FIX 1923 { 1924 TextWidget ctx = (TextWidget)XtParent(w); 1925 ctx->text.redisplay_needed = True; 1926 _XawTextBuildLineTable(ctx, ctx->text.lt.top, True); 1927 } 1928#endif 1929} 1930