1/* 2 * Copyright 1991 by OMRON Corporation 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of OMRON not be used in advertising 9 * or publicity pertaining to distribution of the software without specific, 10 * written prior permission. OMRON makes no representations about the 11 * suitability of this software for any purpose. It is provided "as is" 12 * without express or implied warranty. 13 * 14 * OMRON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL OMRON BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 * 22 * Author: Li Yuhong OMRON Corporation 23 */ 24 25/*********************************************************** 26 27Copyright 1987, 1988, 1994, 1998 The Open Group 28 29Permission to use, copy, modify, distribute, and sell this software and its 30documentation for any purpose is hereby granted without fee, provided that 31the above copyright notice appear in all copies and that both that 32copyright notice and this permission notice appear in supporting 33documentation. 34 35The above copyright notice and this permission notice shall be included in 36all copies or substantial portions of the Software. 37 38THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 39IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 40FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 41OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 42AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 43CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 44 45Except as contained in this notice, the name of The Open Group shall not be 46used in advertising or otherwise to promote the sale, use or other dealings 47in this Software without prior written authorization from The Open Group. 48 49 50Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. 51 52 All Rights Reserved 53 54Permission to use, copy, modify, and distribute this software and its 55documentation for any purpose and without fee is hereby granted, 56provided that the above copyright notice appear in all copies and that 57both that copyright notice and this permission notice appear in 58supporting documentation, and that the name of Digital not be 59used in advertising or publicity pertaining to distribution of the 60software without specific, written prior permission. 61 62DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 63ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 64DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 65ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 66WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 67ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 68SOFTWARE. 69 70******************************************************************/ 71 72#ifdef HAVE_CONFIG_H 73#include <config.h> 74#endif 75#include <X11/IntrinsicP.h> 76#include <X11/StringDefs.h> 77#include <X11/Xatom.h> 78#include <X11/Xaw/XawInit.h> 79#include <X11/Xaw/MultiSinkP.h> 80#include <X11/Xaw/MultiSrcP.h> 81#include <X11/Xaw/TextP.h> 82#include "XawI18n.h" 83#include <stdio.h> 84#include <ctype.h> 85#include "Private.h" 86 87#ifdef GETLASTPOS 88#undef GETLASTPOS /* We will use our own GETLASTPOS */ 89#endif 90 91#define GETLASTPOS \ 92 XawTextSourceScan(source, 0, XawstAll, XawsdRight, 1, True) 93 94/* 95 * Class Methods 96 */ 97static void XawMultiSinkClassInitialize(void); 98static void XawMultiSinkInitialize(Widget, Widget, ArgList, Cardinal*); 99static void XawMultiSinkDestroy(Widget); 100static void XawMultiSinkResize(Widget); 101static Boolean XawMultiSinkSetValues(Widget, Widget, Widget, 102 ArgList, Cardinal*); 103static int MaxLines(Widget, unsigned int); 104static int MaxHeight(Widget, int); 105static void SetTabs(Widget, int, short*); 106static void DisplayText(Widget, int, int, 107 XawTextPosition, XawTextPosition, Bool); 108static void InsertCursor(Widget, int, int, XawTextInsertState); 109static void FindPosition(Widget, XawTextPosition, int, int, Bool, 110 XawTextPosition*, int*, int*); 111static void FindDistance(Widget, XawTextPosition, int, XawTextPosition, int*, 112 XawTextPosition*, int*); 113static void Resolve(Widget, XawTextPosition, int, int, XawTextPosition*); 114static void GetCursorBounds(Widget, XRectangle*); 115 116/* 117 * Prototypes 118 */ 119static void GetGC(MultiSinkObject); 120static int CharWidth(MultiSinkObject, XFontSet, int, wchar_t); 121static unsigned int PaintText(Widget w, GC gc, int x, int y, 122 wchar_t *buf, int len, Bool); 123 124/* 125 * Defined in TextSink.c 126 */ 127void _XawTextSinkClearToBackground(Widget, int, int, unsigned, unsigned); 128 129/* 130 * Initialization 131 */ 132static wchar_t wspace[2]; 133 134#define offset(field) XtOffsetOf(MultiSinkRec, multi_sink.field) 135static XtResource resources[] = { 136 { 137 XtNfontSet, 138 XtCFontSet, 139 XtRFontSet, 140 sizeof(XFontSet), 141 offset(fontset), 142 XtRString, 143 (XtPointer)XtDefaultFontSet 144 }, 145 { 146 XtNecho, 147 XtCOutput, 148 XtRBoolean, 149 sizeof(Boolean), 150 offset(echo), 151 XtRImmediate, 152 (XtPointer)True 153 }, 154 { 155 XtNdisplayNonprinting, 156 XtCOutput, 157 XtRBoolean, 158 sizeof(Boolean), 159 offset(display_nonprinting), 160 XtRImmediate, 161 (XtPointer)True 162 }, 163}; 164#undef offset 165 166#define SuperClass (&textSinkClassRec) 167MultiSinkClassRec multiSinkClassRec = { 168 /* object */ 169 { 170 (WidgetClass)SuperClass, /* superclass */ 171 "MultiSink", /* class_name */ 172 sizeof(MultiSinkRec), /* widget_size */ 173 XawMultiSinkClassInitialize, /* class_initialize */ 174 NULL, /* class_part_initialize */ 175 False, /* class_inited */ 176 XawMultiSinkInitialize, /* initialize */ 177 NULL, /* initialize_hook */ 178 NULL, /* obj1 */ 179 NULL, /* obj2 */ 180 0, /* obj3 */ 181 resources, /* resources */ 182 XtNumber(resources), /* num_resources */ 183 NULLQUARK, /* xrm_class */ 184 False, /* obj4 */ 185 False, /* obj5 */ 186 False, /* obj6 */ 187 False, /* obj7 */ 188 XawMultiSinkDestroy, /* destroy */ 189 (XtProc)XawMultiSinkResize, /* obj8 */ 190 NULL, /* obj9 */ 191 XawMultiSinkSetValues, /* set_values */ 192 NULL, /* set_values_hook */ 193 NULL, /* obj10 */ 194 NULL, /* get_values_hook */ 195 NULL, /* obj11 */ 196 XtVersion, /* version */ 197 NULL, /* callback_private */ 198 NULL, /* obj12 */ 199 NULL, /* obj13 */ 200 NULL, /* obj14 */ 201 NULL, /* extension */ 202 }, 203 /* text_sink */ 204 { 205 DisplayText, /* DisplayText */ 206 InsertCursor, /* InsertCursor */ 207 XtInheritClearToBackground, /* ClearToBackground */ 208 FindPosition, /* FindPosition */ 209 FindDistance, /* FindDistance */ 210 Resolve, /* Resolve */ 211 MaxLines, /* MaxLines */ 212 MaxHeight, /* MaxHeight */ 213 SetTabs, /* SetTabs */ 214 GetCursorBounds, /* GetCursorBounds */ 215 }, 216 /* multi_sink */ 217 { 218 NULL, /* extension */ 219 } 220}; 221 222WidgetClass multiSinkObjectClass = (WidgetClass)&multiSinkClassRec; 223 224/* 225 * Implementation 226 */ 227static int 228CharWidth(MultiSinkObject sink, XFontSet fontset, int x, wchar_t c) 229{ 230 int width = 0; 231 232 if (c == _Xaw_atowc(XawLF)) 233 return (0); 234 235 if (c == _Xaw_atowc(XawTAB)) { 236 int i; 237 Position *tab; 238 239 width = x; 240 /* Adjust for Left Margin. */ 241 x -= ((TextWidget)XtParent((Widget)sink))->text.left_margin; 242 243 i = 0; 244 tab = sink->text_sink.tabs; 245 /*CONSTCOND*/ 246 while (1) { 247 if (x < *tab) 248 return (*tab - x); 249 /* Start again */ 250 if (++i >= sink->text_sink.tab_count) { 251 x -= *tab; 252 i = 0; 253 tab = sink->text_sink.tabs; 254 if (width == x) 255 return (0); 256 } 257 else 258 ++tab; 259 } 260 /*NOTREACHED*/ 261 } 262 263 if (XwcTextEscapement(fontset, &c, 1) == 0) { 264 if (sink->multi_sink.display_nonprinting) 265 c = _Xaw_atowc('@'); 266 else 267 c = _Xaw_atowc(XawSP); 268 } 269 270 /* 271 * if more efficiency(suppose one column is one ASCII char) 272 273 width = XwcGetColumn(fontset->font_charset, fontset->num_of_fonts, c) * 274 fontset->font_struct_list[0]->min_bounds.width; 275 * 276 * WARNING: Very Slower!!! 277 * 278 * Li Yuhong. 279 */ 280 281 width = XwcTextEscapement(fontset, &c, 1); 282 283 return (width); 284} 285 286/* 287 * Function: 288 * PaintText 289 * 290 * Parameters: 291 * w - text sink object 292 * gc - gc to paint text 293 * x - location to paint the text 294 * y - "" 295 * buf - buffer and length of text to paint 296 * len - "" 297 * clear_bg - clear background before drawing ? 298 * 299 * Description: 300 * Actually paints the text into the window. 301 * 302 * Returns: 303 * The width of the text painted 304 */ 305static unsigned int 306PaintText(Widget w, GC gc, int x, int y, wchar_t *buf, int len, Bool clear_bg) 307{ 308 MultiSinkObject sink = (MultiSinkObject)w; 309 TextWidget ctx = (TextWidget)XtParent(w); 310 XFontSet fontset = sink->multi_sink.fontset; 311 unsigned int width = (unsigned)XwcTextEscapement(fontset, buf, len); 312 313 if (((int)width) <= -x) /* Don't draw if we can't see it */ 314 return (width); 315 316 if (clear_bg) { 317 XFontSetExtents *ext = XExtentsOfFontSet(fontset); 318 319 _XawTextSinkClearToBackground(w, x, y - abs(ext->max_logical_extent.y), 320 width, ext->max_logical_extent.height); 321 XwcDrawString(XtDisplay(ctx), XtWindow(ctx), fontset, gc, x, y, buf, len); 322 } 323 else 324 XwcDrawImageString(XtDisplay(ctx), XtWindow(ctx), fontset, gc, 325 x, y, buf, len); 326 327 return (width); 328} 329 330/* Sink Object Functions */ 331/* 332 * This function does not know about drawing more than one line of text 333 */ 334static void 335DisplayText(Widget w, int x, int y, 336 XawTextPosition pos1, XawTextPosition pos2, Bool highlight) 337{ 338 TextWidget ctx = (TextWidget)XtParent(w); 339 MultiSinkObject sink = (MultiSinkObject)w; 340 XFontSet fontset = sink->multi_sink.fontset; 341 Widget source = XawTextGetSource(XtParent(w)); 342 wchar_t buf[256]; 343 XFontSetExtents *ext = XExtentsOfFontSet(fontset); 344 int j, k; 345 XawTextBlock blk; 346 GC gc, invgc, tabgc; 347 int max_x; 348 Bool clear_bg; 349 350 if (!sink->multi_sink.echo || !ctx->text.lt.lines) 351 return; 352 353 max_x = (int)XtWidth(ctx) - ctx->text.r_margin.right; 354 clear_bg = !highlight && ctx->core.background_pixmap != XtUnspecifiedPixmap; 355 356 gc = highlight ? sink->multi_sink.invgc : sink->multi_sink.normgc; 357 invgc = highlight ? sink->multi_sink.normgc : sink->multi_sink.invgc; 358 359 if (highlight && sink->multi_sink.xorgc) 360 tabgc = sink->multi_sink.xorgc; 361 else 362 tabgc = invgc; 363 364 y += abs(ext->max_logical_extent.y); 365 for (j = 0; pos1 < pos2;) { 366 pos1 = XawTextSourceRead(source, pos1, &blk, (int) (pos2 - pos1)); 367 for (k = 0; k < blk.length; k++) { 368 if ((unsigned) j >= (sizeof(buf) / sizeof(wchar_t)) - 1) { 369 /* buffer full, dump the text */ 370 if ((x = (int)((unsigned)x + PaintText(w, gc, x, y, buf, j, clear_bg))) >= max_x) 371 return; 372 j = 0; 373 } 374 buf[j] = ((wchar_t *)blk.ptr)[k]; 375 if (buf[j] == _Xaw_atowc(XawLF)) 376 continue; 377 378 else if (buf[j] == _Xaw_atowc(XawTAB)) { 379 unsigned int width; 380 381 if (j != 0 && 382 (x = (int)((unsigned)x + PaintText(w, gc, x, y, buf, j, clear_bg))) >= max_x) 383 return; 384 385 width = (unsigned)CharWidth(sink, fontset, x, _Xaw_atowc(XawTAB)); 386 if (clear_bg) 387 _XawTextSinkClearToBackground(w, 388 x, y - abs(ext->max_logical_extent.y), 389 width, ext->max_logical_extent.height); 390 else 391 XFillRectangle(XtDisplayOfObject(w), XtWindowOfObject(w), 392 tabgc, x, 393 y - abs(ext->max_logical_extent.y), 394 width, 395 ext->max_logical_extent.height); 396 x = (int)((unsigned)x + width); 397 j = -1; 398 } 399 else if (XwcTextEscapement(sink->multi_sink.fontset, &buf[j], 1) 400 == 0) { 401 if (sink->multi_sink.display_nonprinting) 402 buf[j] = _Xaw_atowc('@'); 403 else 404 buf[j] = _Xaw_atowc(XawSP); 405 } 406 j++; 407 } 408 } 409 410 if (j > 0) 411 (void)PaintText(w, gc, x, y, buf, j, clear_bg); 412} 413 414/* 415 * Function: 416 * GetCursorBounds 417 * 418 * Parameters: 419 * w - text sink object 420 * rect - X rectangle to return the cursor bounds 421 * 422 * Description: 423 * Returns the size and location of the cursor. 424 */ 425static void 426GetCursorBounds(Widget w, XRectangle *rect) 427{ 428 MultiSinkObject sink = (MultiSinkObject)w; 429 430 rect->width = (unsigned short)CharWidth(sink, sink->multi_sink.fontset, 0, _Xaw_atowc(XawSP)); 431 rect->height = (XExtentsOfFontSet(sink->multi_sink.fontset) 432 ->max_logical_extent.height); 433 rect->x = sink->multi_sink.cursor_x; 434 rect->y = (short)(sink->multi_sink.cursor_y - (short)rect->height); 435} 436 437/* 438 * The following procedure manages the "insert" cursor 439 */ 440static void 441InsertCursor(Widget w, int x, int y, XawTextInsertState state) 442{ 443 MultiSinkObject sink = (MultiSinkObject)w; 444 XFontSet fontset = sink->multi_sink.fontset; 445 Widget ctx = XtParent(w); 446 XawTextPosition position = XawTextGetInsertionPoint(ctx); 447 448 if (XtIsRealized(ctx)) { 449 int fheight, fdiff; 450 XawTextBlock block; 451 wchar_t c; 452 XawTextPosition selection_start, selection_end; 453 Boolean has_selection; 454 XFontSetExtents *ext = XExtentsOfFontSet(fontset); 455 456 XawTextGetSelectionPos((Widget)ctx, &selection_start, &selection_end); 457 has_selection = selection_start != selection_end; 458 459 fheight = ext->max_logical_extent.height; 460 fdiff = fheight - abs(ext->max_logical_extent.y); 461 462 if ((sink->multi_sink.cursor_position != position || state == XawisOff) 463 && !has_selection && sink->multi_sink.laststate != XawisOff) { 464 wchar_t *ochar; 465 466 (void)XawTextSourceRead(XawTextGetSource(ctx), 467 sink->multi_sink.cursor_position, 468 &block, 1); 469 if (!block.length) 470 ochar = NULL; 471 else { 472 c = ((wchar_t *)block.ptr)[0]; 473 if (c == _Xaw_atowc(XawLF)) 474 ochar = NULL; 475 else if (c == _Xaw_atowc(XawTAB)) 476 ochar = wspace; 477 else 478 ochar = (wchar_t *)block.ptr; 479 } 480 481 if (!ochar) 482 _XawTextSinkClearToBackground(w, sink->multi_sink.cursor_x, 483 (sink->multi_sink.cursor_y - 1 - 484 fheight), 485 (unsigned)CharWidth(sink, fontset, 0, wspace[0]), 486 (unsigned)fheight); 487 else { 488 if (XwcTextEscapement(sink->multi_sink.fontset, ochar, 1) != 0) 489 DisplayText(w, sink->multi_sink.cursor_x, 490 sink->multi_sink.cursor_y - 1 - fheight, 491 sink->multi_sink.cursor_position, 492 sink->multi_sink.cursor_position + 1, 493 False); 494 else 495 PaintText(w, sink->multi_sink.normgc, 496 sink->multi_sink.cursor_x, 497 sink->multi_sink.cursor_y - 1 - fdiff, 498 ochar, 1, 499 ctx->core.background_pixmap != XtUnspecifiedPixmap); 500 } 501 } 502 503 if (!has_selection && state != XawisOff) { 504 wchar_t *nchar; 505 Boolean focus = ((TextWidget)ctx)->text.hasfocus; 506 507 (void)XawTextSourceRead(XawTextGetSource(ctx), 508 position, &block, 1); 509 c = ((wchar_t *)block.ptr)[0]; 510 if (!block.length || c == _Xaw_atowc(XawLF) 511 || c == _Xaw_atowc(XawTAB)) 512 nchar = wspace; 513 else 514 nchar = (wchar_t *)block.ptr; 515 516 if (focus) { 517 if (XwcTextEscapement(sink->multi_sink.fontset, nchar, 1) != 0) 518 XwcDrawImageString(XtDisplay(ctx), XtWindow(ctx), 519 fontset, sink->multi_sink.invgc, 520 x, (y - 1 - fdiff), nchar, 1); 521 else 522 DisplayText(w, x, y - 1 - fheight, 523 position, position + 1, True); 524 } 525 else 526 XDrawRectangle(XtDisplay(ctx), XtWindow(ctx), 527 sink->multi_sink.xorgc ? 528 sink->multi_sink.xorgc : sink->multi_sink.normgc, 529 x, y - 1 - fheight, 530 (unsigned)(CharWidth(sink, fontset, 0, *nchar) - 1), 531 (unsigned)(fheight - 1)); 532 } 533 } 534 535 sink->multi_sink.cursor_x = (short)x; 536 sink->multi_sink.cursor_y = (short)y; 537 sink->multi_sink.laststate = state; 538 sink->multi_sink.cursor_position = position; 539} 540 541/* 542 * Given two positions, find the distance between them 543 */ 544static void 545FindDistance(Widget w, XawTextPosition fromPos, int fromx, 546 XawTextPosition toPos, int *resWidth, 547 XawTextPosition *resPos, int *resHeight) 548{ 549 MultiSinkObject sink = (MultiSinkObject)w; 550 XFontSet fontset = sink->multi_sink.fontset; 551 TextWidget ctx = (TextWidget)XtParent(w); 552 Widget source = ctx->text.source; 553 XawTextPosition idx, pos; 554 XFontSetExtents *ext = XExtentsOfFontSet(fontset); 555 XawTextBlock blk; 556 int i, rWidth; 557 558 pos = XawTextSourceRead(source, fromPos, &blk, (int)(toPos - fromPos)); 559 rWidth = 0; 560 for (i = 0, idx = fromPos; idx < toPos; i++, idx++) { 561 wchar_t c; 562 563 if (i >= blk.length) { 564 i = 0; 565 XawTextSourceRead(source, pos, &blk, (int)(toPos - pos)); 566 if (blk.length == 0) 567 break; 568 } 569 c = ((wchar_t *)blk.ptr)[i]; 570 rWidth += CharWidth(sink, fontset, fromx + rWidth, c); 571 if (c == _Xaw_atowc(XawLF)) { 572 idx++; 573 break; 574 } 575 } 576 577 *resPos = idx; 578 *resWidth = rWidth; 579 *resHeight = ext->max_logical_extent.height; 580} 581 582static void 583FindPosition(Widget w, XawTextPosition fromPos, int fromx, int width, 584 Bool stopAtWordBreak, XawTextPosition *resPos, int *resWidth, 585 int *resHeight) 586{ 587 MultiSinkObject sink = (MultiSinkObject)w; 588 TextWidget ctx = (TextWidget)XtParent(w); 589 Widget source = ctx->text.source; 590 XFontSet fontset = sink->multi_sink.fontset; 591 XawTextPosition idx, pos, whiteSpacePosition = 0; 592 int i, lastWidth, whiteSpaceWidth, rWidth; 593 Boolean whiteSpaceSeen; 594 wchar_t c; 595 XFontSetExtents *ext = XExtentsOfFontSet(fontset); 596 XawTextBlock blk; 597 598 pos = XawTextSourceRead(source, fromPos, &blk, BUFSIZ); 599 rWidth = lastWidth = whiteSpaceWidth = 0; 600 whiteSpaceSeen = False; 601 c = 0; 602 603 for (i = 0, idx = fromPos; rWidth <= width; i++, idx++) { 604 if (i >= blk.length) { 605 i = 0; 606 pos = XawTextSourceRead(source, pos, &blk, BUFSIZ); 607 if (blk.length == 0) 608 break; 609 } 610 c = ((wchar_t *)blk.ptr)[i]; 611 lastWidth = rWidth; 612 rWidth += CharWidth(sink, fontset, fromx + rWidth, c); 613 614 if (c == _Xaw_atowc(XawLF)) { 615 idx++; 616 break; 617 } 618 else if ((c == _Xaw_atowc(XawSP) || c == _Xaw_atowc(XawTAB)) 619 && rWidth <= width) { 620 whiteSpaceSeen = True; 621 whiteSpacePosition = idx; 622 whiteSpaceWidth = rWidth; 623 } 624 } 625 626 if (rWidth > width && idx > fromPos) { 627 idx--; 628 rWidth = lastWidth; 629 if (stopAtWordBreak && whiteSpaceSeen) { 630 idx = whiteSpacePosition + 1; 631 rWidth = whiteSpaceWidth; 632 } 633 } 634 635 if (idx >= ctx->text.lastPos && c != _Xaw_atowc(XawLF)) 636 idx = ctx->text.lastPos + 1; 637 638 *resPos = idx; 639 *resWidth = rWidth; 640 *resHeight = ext->max_logical_extent.height; 641} 642 643static void 644Resolve(Widget w, XawTextPosition pos, int fromx, int width, 645 XawTextPosition *pos_return) 646{ 647 int resWidth, resHeight; 648 Widget source = XawTextGetSource(XtParent(w)); 649 650 FindPosition(w, pos, fromx, width, False, pos_return, &resWidth, &resHeight); 651 if (*pos_return > GETLASTPOS) 652 *pos_return = GETLASTPOS; 653} 654 655static void 656GetGC(MultiSinkObject sink) 657{ 658 XtGCMask valuemask = (GCGraphicsExposures | GCClipXOrigin | 659 GCForeground | GCBackground); 660 XGCValues values = { 661 /* XXX We dont want to share a gc that will change the clip-mask */ 662 .clip_x_origin = (int)(long)sink, 663 .clip_mask = None, 664 .graphics_exposures = False, 665 666 .foreground = sink->text_sink.foreground, 667 .background = sink->text_sink.background 668 }; 669 670 sink->multi_sink.normgc = XtAllocateGC((Widget)sink, 0, valuemask, &values, 671 GCFont | GCClipMask, 0); 672 673 values.foreground = sink->text_sink.background; 674#ifndef OLDXAW 675 values.background = sink->text_sink.cursor_color; 676#else 677 values.background = sink->text_sink.foreground; 678#endif 679 sink->multi_sink.invgc = XtAllocateGC((Widget)sink, 0, valuemask, &values, 680 GCFont | GCClipMask, 0); 681#ifndef OLDXAW 682 if (sink->text_sink.cursor_color != sink->text_sink.foreground) { 683 values.foreground = sink->text_sink.cursor_color; 684 values.background = sink->text_sink.foreground; 685 sink->multi_sink.xorgc = XtAllocateGC((Widget)sink, 0, valuemask, 686 &values, GCFont | GCClipMask, 0); 687 } 688 else 689#endif /* OLDXAW */ 690 sink->multi_sink.xorgc = NULL; 691 692 XawMultiSinkResize((Widget)sink); 693} 694 695static void 696XawMultiSinkClassInitialize(void) 697{ 698 wspace[0] = _Xaw_atowc(XawSP); 699 XawInitializeWidgetSet(); 700} 701 702/* 703 * Function: 704 * XawMultiSinkInitialize 705 * 706 * Parameters: 707 * request - requested and new values for the object instance 708 * cnew - "" 709 * 710 * Description: 711 * Initializes the TextSink Object. 712 */ 713/* ARGSUSED */ 714static void 715XawMultiSinkInitialize(Widget request _X_UNUSED, Widget cnew, 716 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 717{ 718 MultiSinkObject sink = (MultiSinkObject)cnew; 719 720 GetGC(sink); 721 722 if (!sink->multi_sink.fontset) XtError("Aborting: no fontset found\n"); 723 724 sink->multi_sink.cursor_position = 0; 725 sink->multi_sink.laststate = XawisOff; 726 sink->multi_sink.cursor_x = sink->multi_sink.cursor_y = 0; 727} 728 729/* 730 * Function: 731 * XawMultiSinkDestroy 732 * 733 * Parameters: 734 * w - MultiSink Object 735 * 736 * Description: 737 * This function cleans up when the object is destroyed. 738 */ 739static void 740XawMultiSinkDestroy(Widget w) 741{ 742 MultiSinkObject sink = (MultiSinkObject)w; 743 744 XtReleaseGC(w, sink->multi_sink.normgc); 745 XtReleaseGC(w, sink->multi_sink.invgc); 746 if (sink->multi_sink.xorgc) 747 XtReleaseGC(w, sink->multi_sink.xorgc); 748 sink->multi_sink.normgc = 749 sink->multi_sink.invgc = 750 sink->multi_sink.xorgc = NULL; 751} 752 753static void 754XawMultiSinkResize(Widget w) 755{ 756 TextWidget ctx = (TextWidget)XtParent(w); 757 MultiSinkObject sink = (MultiSinkObject)w; 758 XRectangle rect; 759 int width, height; 760 761 if (w->core.widget_class != multiSinkObjectClass) 762 return; 763 764 rect.x = ctx->text.r_margin.left; 765 rect.y = ctx->text.r_margin.top; 766 width = (int)XtWidth(ctx) - 767 (int)ctx->text.r_margin.right - (int)ctx->text.r_margin.left; 768 height = (int)XtHeight(ctx) - 769 (int)ctx->text.r_margin.top - (int)ctx->text.r_margin.bottom; 770 rect.width = (unsigned short)width; 771 rect.height = (unsigned short)height; 772 773 if (sink->multi_sink.normgc) { 774 if (width >= 0 && height >= 0) 775 XSetClipRectangles(XtDisplay((Widget)ctx), sink->multi_sink.normgc, 776 0, 0, &rect, 1, Unsorted); 777 else 778 XSetClipMask(XtDisplay((Widget)ctx), sink->multi_sink.normgc, None); 779 } 780 if (sink->multi_sink.invgc) { 781 if (width >= 0 && height >= 0) 782 XSetClipRectangles(XtDisplay((Widget)ctx), sink->multi_sink.invgc, 783 0, 0, &rect, 1, Unsorted); 784 else 785 XSetClipMask(XtDisplay((Widget)ctx), sink->multi_sink.invgc, None); 786 } 787 if (sink->multi_sink.xorgc) { 788 if (width >= 0 && height >= 0) 789 XSetClipRectangles(XtDisplay((Widget)ctx), sink->multi_sink.xorgc, 790 0, 0, &rect, 1, Unsorted); 791 else 792 XSetClipMask(XtDisplay((Widget)ctx), sink->multi_sink.xorgc, None); 793 } 794} 795 796/* 797 * Function: 798 * XawMultiSinkSetValues 799 * 800 * Parameters: 801 * current - current state of the object 802 * request - what was requested 803 * cnew - what the object will become 804 * 805 * Description: 806 * Sets the values for the MultiSink. 807 * 808 * Returns: 809 * True if redisplay is needed 810 */ 811/*ARGSUSED*/ 812static Boolean 813XawMultiSinkSetValues(Widget current, Widget request _X_UNUSED, Widget cnew, 814 ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 815{ 816 MultiSinkObject w = (MultiSinkObject)cnew; 817 MultiSinkObject old_w = (MultiSinkObject)current; 818 819 /* Font set is not in the GC! Do not make a new GC when font set changes! */ 820 821 if (w->multi_sink.fontset != old_w->multi_sink.fontset) { 822 ((TextWidget)XtParent(cnew))->text.redisplay_needed = True; 823#ifndef NO_TAB_FIX 824 SetTabs((Widget)w, w->text_sink.tab_count, w->text_sink.char_tabs); 825#endif 826 } 827 828 if (w->text_sink.background != old_w->text_sink.background 829 || w->text_sink.foreground != old_w->text_sink.foreground 830#ifndef OLDXAW 831 || w->text_sink.cursor_color != old_w->text_sink.cursor_color 832#endif 833 ) { 834 XtReleaseGC(cnew, w->multi_sink.normgc); 835 XtReleaseGC(cnew, w->multi_sink.invgc); 836 if (w->multi_sink.xorgc) 837 XtReleaseGC(cnew, w->multi_sink.xorgc); 838 GetGC(w); 839 ((TextWidget)XtParent(cnew))->text.redisplay_needed = True; 840 } 841 else if (w->multi_sink.echo != old_w->multi_sink.echo 842 || w->multi_sink.display_nonprinting 843 != old_w->multi_sink.display_nonprinting) 844 ((TextWidget)XtParent(cnew))->text.redisplay_needed = True; 845 846 return (False); 847} 848 849/* 850 * Function: 851 * MaxLines 852 * 853 * Parameters: 854 * w - MultiSink Object 855 * height - height to fit lines into 856 * 857 * Description: 858 * Finds the Maximum number of lines that will fit in a given height. 859 * 860 * Returns: 861 * The number of lines that will fit 862 */ 863/*ARGSUSED*/ 864static int 865MaxLines(Widget w, unsigned int height) 866{ 867 MultiSinkObject sink = (MultiSinkObject)w; 868 int font_height; 869 XFontSetExtents *ext = XExtentsOfFontSet(sink->multi_sink.fontset); 870 871 font_height = ext->max_logical_extent.height; 872 return (int)(height / (unsigned)font_height); 873} 874 875/* 876 * Function: 877 * MaxHeight 878 * 879 * Parameters: 880 * w - MultiSink Object 881 * lines - number of lines 882 * 883 * Description: 884 * Finds the Minimum height that will contain a given number lines. 885 * Returns: 886 * The height 887 */ 888/*ARGSUSED*/ 889static int 890MaxHeight(Widget w, int lines) 891{ 892 MultiSinkObject sink = (MultiSinkObject)w; 893 XFontSetExtents *ext = XExtentsOfFontSet(sink->multi_sink.fontset); 894 895 return (lines * ext->max_logical_extent.height); 896} 897 898/* 899 * Function: 900 * SetTabs 901 * 902 * Arguments: 903 * w - MultiSink Object 904 * tab_count - number of tabs in the list 905 * tabs - text positions of the tabs 906 * 907 * Description: 908 * Sets the Tab stops. 909 */ 910static void 911SetTabs(Widget w, int tab_count, short* tabs) 912{ 913 MultiSinkObject sink = (MultiSinkObject)w; 914 int i; 915 Atom XA_FIGURE_WIDTH; 916 unsigned long figure_width = 0; 917 XFontStruct *font; 918 919 /* 920 * Bug: 921 * Suppose the first font of fontset stores the unit of column. 922 * 923 * By Li Yuhong, Mar. 14, 1991 924 */ 925 { 926 XFontStruct **f_list; 927 char **f_name; 928 929 (void)XFontsOfFontSet(sink->multi_sink.fontset, &f_list, &f_name); 930 font = f_list[0]; 931 } 932 933 /* 934 * Find the figure width of the current font 935 */ 936 XA_FIGURE_WIDTH = XInternAtom(XtDisplayOfObject(w), "FIGURE_WIDTH", False); 937 if (XA_FIGURE_WIDTH != None 938 && (!XGetFontProperty(font, XA_FIGURE_WIDTH, &figure_width) 939 || figure_width == 0)) { 940 if (font->per_char && font->min_char_or_byte2 <= '$' 941 && font->max_char_or_byte2 >= '$') 942 figure_width = (unsigned long)font->per_char['$' - font->min_char_or_byte2].width; 943 else 944 figure_width = (unsigned long)font->max_bounds.width; 945 } 946 947 if (tab_count > sink->text_sink.tab_count) { 948 sink->text_sink.tabs = (Position *) 949 XtRealloc((char *)sink->text_sink.tabs, 950 (Cardinal)((unsigned long)tab_count * sizeof(Position))); 951 sink->text_sink.char_tabs = (short *) 952 XtRealloc((char *)sink->text_sink.char_tabs, 953 (Cardinal)((unsigned long)tab_count * sizeof(short))); 954 } 955 956 for (i = 0 ; i < tab_count ; i++) { 957 sink->text_sink.tabs[i] = (Position)((unsigned long)tabs[i] * figure_width); 958 sink->text_sink.char_tabs[i] = tabs[i]; 959 } 960 961 sink->text_sink.tab_count = tab_count; 962 963#ifndef NO_TAB_FIX 964 ((TextWidget)XtParent(w))->text.redisplay_needed = True; 965#endif 966} 967 968void 969_XawMultiSinkPosToXY(Widget w, XawTextPosition pos, Position *x, Position *y) 970{ 971 MultiSinkObject sink = (MultiSinkObject)((TextWidget)w)->text.sink; 972 XFontSetExtents *ext = XExtentsOfFontSet(sink->multi_sink.fontset); 973 974 _XawTextPosToXY(w, pos, x, y); 975 *y = (Position)(*y + abs(ext->max_logical_extent.y)); 976} 977