|
|
1.1 ! root 1: #ifndef lint ! 2: static char rcsid[] = "$Header: AsciiSink.c,v 1.3 87/09/13 13:28:59 swick Exp $"; ! 3: #endif lint ! 4: ! 5: /* ! 6: * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. ! 7: * ! 8: * All Rights Reserved ! 9: * ! 10: * Permission to use, copy, modify, and distribute this software and its ! 11: * documentation for any purpose and without fee is hereby granted, ! 12: * provided that the above copyright notice appear in all copies and that ! 13: * both that copyright notice and this permission notice appear in ! 14: * supporting documentation, and that the name of Digital Equipment ! 15: * Corporation not be used in advertising or publicity pertaining to ! 16: * distribution of the software without specific, written prior permission. ! 17: * ! 18: * ! 19: * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ! 20: * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ! 21: * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ! 22: * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, ! 23: * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ! 24: * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ! 25: * SOFTWARE. ! 26: */ ! 27: #include "Xlib.h" ! 28: #include "Xutil.h" ! 29: #include "Xatom.h" ! 30: #include "Intrinsic.h" ! 31: #include "Text.h" ! 32: #include "TextP.h" ! 33: #include "Atoms.h" ! 34: ! 35: #define GETLASTPOS (*(source->scan))(source, 0, XtstFile, XtsdRight, 1, TRUE) ! 36: /* Private Ascii TextSink Definitions */ ! 37: ! 38: static unsigned bufferSize = 200; ! 39: ! 40: typedef struct _AsciiSinkData { ! 41: Pixel foreground; ! 42: GC normgc, invgc, xorgc; ! 43: XFontStruct *font; ! 44: int tabwidth; ! 45: Pixmap insertCursorOn; ! 46: Pixmap insertCursorOff; ! 47: InsertState laststate; ! 48: } AsciiSinkData, *AsciiSinkPtr; ! 49: ! 50: static char *buf; ! 51: ! 52: /* XXX foreground default should be XtDefaultFGPixel. How do i do that?? */ ! 53: ! 54: static XtResource SinkResources[] = { ! 55: {XtNfont, XtCFont, XrmRFontStruct, sizeof (XFontStruct *), ! 56: XtOffset(AsciiSinkPtr, font), XrmRString, "Fixed"}, ! 57: {XtNforeground, XtCColor, XrmRPixel, sizeof (int), ! 58: XtOffset(AsciiSinkPtr, foreground), XrmRString, "Black"}, ! 59: }; ! 60: ! 61: /* Utilities */ ! 62: ! 63: static int CharWidth (data, x, c) ! 64: AsciiSinkData *data; ! 65: int x; ! 66: char c; ! 67: { ! 68: int width, nonPrinting; ! 69: XFontStruct *font = data->font; ! 70: ! 71: if (c == '\t') ! 72: /* This is totally bogus!! need to know tab settings etc.. */ ! 73: return data->tabwidth - (x % data->tabwidth); ! 74: if (c == LF) ! 75: c = SP; ! 76: nonPrinting = (c < SP); ! 77: if (nonPrinting) c += '@'; ! 78: ! 79: if (font->per_char && ! 80: (c >= font->min_char_or_byte2 && c <= font->max_char_or_byte2)) ! 81: width = font->per_char[c - font->min_char_or_byte2].width; ! 82: else ! 83: width = font->min_bounds.width; ! 84: ! 85: if (nonPrinting) ! 86: width += CharWidth(data, x, '^'); ! 87: ! 88: return width; ! 89: } ! 90: ! 91: /* Sink Object Functions */ ! 92: ! 93: #define LBEARING(x) \ ! 94: ((font->per_char != NULL && \ ! 95: ((x) >= font->min_char_or_byte2 && (x) <= font->max_char_or_byte2)) \ ! 96: ? font->per_char[(x) - font->min_char_or_byte2].lbearing \ ! 97: : font->min_bounds.lbearing) ! 98: ! 99: static int AsciiDisplayText (w, x, y, pos1, pos2, highlight) ! 100: Widget w; ! 101: Position x, y; ! 102: int highlight; ! 103: XtTextPosition pos1, pos2; ! 104: { ! 105: XtTextSink *sink = ((TextWidget)w)->text.sink; ! 106: XtTextSource *source = ((TextWidget)w)->text.source; ! 107: AsciiSinkData *data = (AsciiSinkData *) sink->data ; ! 108: ! 109: XFontStruct *font = data->font; ! 110: int j, k; ! 111: Dimension width; ! 112: XtTextBlock blk; ! 113: GC gc = highlight ? data->invgc : data->normgc; ! 114: GC invgc = highlight ? data->normgc : data->invgc; ! 115: ! 116: y += font->ascent; ! 117: j = 0; ! 118: while (pos1 < pos2) { ! 119: pos1 = (*(source->read))(source, pos1, &blk, pos2 - pos1); ! 120: for (k = 0; k < blk.length; k++) { ! 121: if (j >= bufferSize - 5) { ! 122: bufferSize *= 2; ! 123: buf = XtRealloc(buf, bufferSize); ! 124: } ! 125: buf[j] = blk.ptr[k]; ! 126: if (buf[j] == LF) ! 127: buf[j] = ' '; ! 128: else if (buf[j] == '\t') { ! 129: XDrawImageString(XtDisplay(w), XtWindow(w), ! 130: gc, x - LBEARING(*buf), y, buf, j); ! 131: buf[j] = 0; ! 132: x += XTextWidth(data->font, buf, j); ! 133: width = CharWidth(data, x, '\t'); ! 134: XFillRectangle(XtDisplay(w), XtWindow(w), invgc, x, ! 135: y - font->ascent, width, ! 136: (Dimension) (data->font->ascent + ! 137: data->font->descent)); ! 138: x += width; ! 139: j = -1; ! 140: } ! 141: else ! 142: if (buf[j] < ' ') { ! 143: buf[j + 1] = buf[j] + '@'; ! 144: buf[j] = '^'; ! 145: j++; ! 146: } ! 147: j++; ! 148: } ! 149: } ! 150: XDrawImageString(XtDisplay(w), XtWindow(w), gc, x - LBEARING(*buf), y, buf, j); ! 151: } ! 152: ! 153: ! 154: static Pixmap CreateInsertCursor(dpy, gc, state) ! 155: Display *dpy; ! 156: GC gc; ! 157: InsertState state; ! 158: { ! 159: XImage image; ! 160: Pixmap insertCursor; ! 161: ! 162: /* stuff for the text insertion cursor */ ! 163: ! 164: # define insertCursor_width 6 ! 165: # define insertCursor_height 3 ! 166: ! 167: static short insertCursor_bits[] = {0x000c, 0x001e, 0x0033}; ! 168: /* static short insertCursor_bits[] = {0xfff3, 0xffe1, 0xffcc}; */ ! 169: static short blank_bits[] = {0x0000, 0x0000, 0x0000}; ! 170: ! 171: image.height = insertCursor_height; ! 172: image.width = insertCursor_width; ! 173: image.xoffset = 0; ! 174: image.format = XYBitmap; ! 175: image.data = (char *) ((state == XtisOn) ? insertCursor_bits : blank_bits); ! 176: /* image.data = (char *) insertCursor_bits;*/ ! 177: image.byte_order = LSBFirst; ! 178: image.bitmap_unit = 16; ! 179: image.bitmap_bit_order = LSBFirst; ! 180: image.bitmap_pad = 16; ! 181: image.depth = 1; ! 182: image.bytes_per_line = ((insertCursor_width+15) / 16) * 2; ! 183: image.bits_per_pixel = 1; ! 184: image.obdata = NULL; ! 185: insertCursor = XCreatePixmap(dpy, DefaultRootWindow(dpy), (Dimension) image.width, ! 186: (Dimension) image.height, ! 187: DefaultDepth(dpy, 0)); ! 188: /* !!! BOGUS -- should otherwise figure out the depth; this code may not ! 189: work on multiple screen displays. ||| */ ! 190: XPutImage(dpy, insertCursor, gc, &image, 0, 0, 0, 0, ! 191: (Dimension)image.width, (Dimension)image.height); ! 192: return insertCursor; ! 193: } ! 194: ! 195: /* ! 196: * The following procedure manages the "insert" cursor. ! 197: */ ! 198: ! 199: static AsciiInsertCursor (w, x, y, state) ! 200: Widget w; ! 201: Position x, y; ! 202: InsertState state; ! 203: { ! 204: XtTextSink *sink = ((TextWidget)w)->text.sink; ! 205: AsciiSinkData *data = (AsciiSinkData *) sink->data; ! 206: ! 207: /* ! 208: XCopyArea(sink->dpy, ! 209: (state == XtisOn) ? data->insertCursorOn : data->insertCursorOff, w, ! 210: data->normgc, 0, 0, insertCursor_width, insertCursor_height, ! 211: x - (insertCursor_width >> 1), y - (insertCursor_height)); ! 212: */ ! 213: if (state != data->laststate) ! 214: XCopyArea(XtDisplay(w), ! 215: data->insertCursorOn, XtWindow(w), ! 216: data->xorgc, 0, 0, insertCursor_width, insertCursor_height, ! 217: x - (insertCursor_width >> 1), y - (insertCursor_height)); ! 218: data->laststate = state; ! 219: } ! 220: ! 221: /* ! 222: * Clear the passed region to the background color. ! 223: */ ! 224: ! 225: static AsciiClearToBackground (w, x, y, width, height) ! 226: Widget w; ! 227: Position x, y; ! 228: Dimension width, height; ! 229: { ! 230: XtTextSink *sink = ((TextWidget)w)->text.sink; ! 231: AsciiSinkData *data = (AsciiSinkData *) sink->data; ! 232: XFillRectangle(XtDisplay(w), XtWindow(w), data->invgc, x, y, width, height); ! 233: } ! 234: ! 235: /* ! 236: * Given two positions, find the distance between them. ! 237: */ ! 238: ! 239: static AsciiFindDistance (w, fromPos, fromx, toPos, ! 240: resWidth, resPos, resHeight) ! 241: Widget w; ! 242: XtTextPosition fromPos; /* First position. */ ! 243: int fromx; /* Horizontal location of first position. */ ! 244: XtTextPosition toPos; /* Second position. */ ! 245: int *resWidth; /* Distance between fromPos and resPos. */ ! 246: int *resPos; /* Actual second position used. */ ! 247: int *resHeight; /* Height required. */ ! 248: { ! 249: XtTextSink *sink = ((TextWidget)w)->text.sink; ! 250: XtTextSource *source = ((TextWidget)w)->text.source; ! 251: ! 252: AsciiSinkData *data; ! 253: register XtTextPosition index, lastPos; ! 254: register char c; ! 255: XtTextBlock blk; ! 256: ! 257: data = (AsciiSinkData *) sink->data; ! 258: /* we may not need this */ ! 259: lastPos = GETLASTPOS; ! 260: (*(source->read))(source, fromPos, &blk, toPos - fromPos); ! 261: *resWidth = 0; ! 262: for (index = fromPos; index != toPos && index < lastPos; index++) { ! 263: if (index - blk.firstPos >= blk.length) ! 264: (*(source->read))(source, index, &blk, toPos - fromPos); ! 265: c = blk.ptr[index - blk.firstPos]; ! 266: if (c == LF) { ! 267: *resWidth += CharWidth(data, fromx + *resWidth, SP); ! 268: index++; ! 269: break; ! 270: } ! 271: *resWidth += CharWidth(data, fromx + *resWidth, c); ! 272: } ! 273: *resPos = index; ! 274: *resHeight = data->font->ascent + data->font->descent; ! 275: } ! 276: ! 277: ! 278: static AsciiFindPosition(w, fromPos, fromx, width, stopAtWordBreak, ! 279: resPos, resWidth, resHeight) ! 280: Widget w; ! 281: XtTextPosition fromPos; /* Starting position. */ ! 282: int fromx; /* Horizontal location of starting position. */ ! 283: int width; /* Desired width. */ ! 284: int stopAtWordBreak; /* Whether the resulting position should be at ! 285: a word break. */ ! 286: XtTextPosition *resPos; /* Resulting position. */ ! 287: int *resWidth; /* Actual width used. */ ! 288: int *resHeight; /* Height required. */ ! 289: { ! 290: XtTextSink *sink = ((TextWidget)w)->text.sink; ! 291: XtTextSource *source = ((TextWidget)w)->text.source; ! 292: AsciiSinkData *data; ! 293: XtTextPosition lastPos, index, whiteSpacePosition; ! 294: int lastWidth, whiteSpaceWidth; ! 295: Boolean whiteSpaceSeen; ! 296: char c; ! 297: XtTextBlock blk; ! 298: data = (AsciiSinkData *) sink->data; ! 299: lastPos = GETLASTPOS; ! 300: ! 301: (*(source->read))(source, fromPos, &blk, bufferSize); ! 302: *resWidth = 0; ! 303: whiteSpaceSeen = FALSE; ! 304: c = 0; ! 305: for (index = fromPos; *resWidth <= width && index < lastPos; index++) { ! 306: lastWidth = *resWidth; ! 307: if (index - blk.firstPos >= blk.length) ! 308: (*(source->read))(source, index, &blk, bufferSize); ! 309: c = blk.ptr[index - blk.firstPos]; ! 310: if (c == LF) { ! 311: *resWidth += CharWidth(data, fromx + *resWidth, SP); ! 312: index++; ! 313: break; ! 314: } ! 315: *resWidth += CharWidth(data, fromx + *resWidth, c); ! 316: if ((c == SP || c == TAB) && *resWidth <= width) { ! 317: whiteSpaceSeen = TRUE; ! 318: whiteSpacePosition = index; ! 319: whiteSpaceWidth = *resWidth; ! 320: } ! 321: } ! 322: if (*resWidth > width && index > fromPos) { ! 323: *resWidth = lastWidth; ! 324: index--; ! 325: if (stopAtWordBreak && whiteSpaceSeen) { ! 326: index = whiteSpacePosition + 1; ! 327: *resWidth = whiteSpaceWidth; ! 328: } ! 329: } ! 330: if (index == lastPos && c != LF) index = lastPos + 1; ! 331: *resPos = index; ! 332: *resHeight = data->font->ascent + data->font->descent; ! 333: } ! 334: ! 335: ! 336: static int AsciiResolveToPosition (w, pos, fromx, width, ! 337: leftPos, rightPos) ! 338: Widget w; ! 339: XtTextPosition pos; ! 340: int fromx,width; ! 341: XtTextPosition *leftPos, *rightPos; ! 342: { ! 343: int resWidth, resHeight; ! 344: XtTextSink *sink = ((TextWidget)w)->text.sink; ! 345: XtTextSource *source = ((TextWidget)w)->text.source; ! 346: ! 347: AsciiFindPosition(w, pos, fromx, width, FALSE, ! 348: leftPos, &resWidth, &resHeight); ! 349: if (*leftPos > GETLASTPOS) ! 350: *leftPos = GETLASTPOS; ! 351: *rightPos = *leftPos; ! 352: } ! 353: ! 354: ! 355: static int AsciiMaxLinesForHeight (w, height) ! 356: Widget w; ! 357: int height; ! 358: { ! 359: AsciiSinkData *data; ! 360: XtTextSink *sink = ((TextWidget)w)->text.sink; ! 361: ! 362: data = (AsciiSinkData *) sink->data; ! 363: return(height / (data->font->ascent + data->font->descent)); ! 364: } ! 365: ! 366: ! 367: static int AsciiMaxHeightForLines (w, lines) ! 368: Widget w; ! 369: int lines; ! 370: { ! 371: AsciiSinkData *data; ! 372: XtTextSink *sink = ((TextWidget)w)->text.sink; ! 373: ! 374: data = (AsciiSinkData *) sink->data; ! 375: return(lines * (data->font->ascent + data->font->descent)); ! 376: } ! 377: ! 378: ! 379: /***** Public routines *****/ ! 380: ! 381: static Boolean initialized = FALSE; ! 382: static XContext asciiSinkContext; ! 383: ! 384: AsciiSinkInitialize() ! 385: { ! 386: if (initialized) ! 387: return; ! 388: initialized = TRUE; ! 389: ! 390: asciiSinkContext = XUniqueContext(); ! 391: ! 392: buf = (char *) XtMalloc(bufferSize); ! 393: } ! 394: ! 395: ! 396: caddr_t XtAsciiSinkCreate (w, args, argCount) ! 397: Widget w; ! 398: ArgList args; ! 399: int argCount; ! 400: { ! 401: XtTextSink *sink; ! 402: AsciiSinkData *data; ! 403: unsigned long valuemask = (GCFont | GCGraphicsExposures | ! 404: GCForeground | GCBackground | GCFunction); ! 405: XGCValues values; ! 406: unsigned long wid; ! 407: XFontStruct *font; ! 408: ! 409: if (!initialized) ! 410: AsciiSinkInitialize(); ! 411: ! 412: sink = (XtTextSink *) XtMalloc(sizeof(XtTextSink)); ! 413: sink->display = AsciiDisplayText; ! 414: sink->insertCursor = AsciiInsertCursor; ! 415: sink->clearToBackground = AsciiClearToBackground; ! 416: sink->findPosition = AsciiFindPosition; ! 417: sink->findDistance = AsciiFindDistance; ! 418: sink->resolve = AsciiResolveToPosition; ! 419: sink->maxLines = AsciiMaxLinesForHeight; ! 420: sink->maxHeight = AsciiMaxHeightForLines; ! 421: sink->data = (int *) XtMalloc(sizeof(AsciiSinkData)); ! 422: data = (AsciiSinkData *) sink->data; ! 423: ! 424: XtGetSubresources (w, data, "subclass", "subclass", ! 425: SinkResources, XtNumber(SinkResources), ! 426: args, argCount); ! 427: ! 428: /* XXX do i have to XLoadQueryFont or does the resource guy do it for me */ ! 429: ! 430: font = data->font; ! 431: values.function = GXcopy; ! 432: values.font = font->fid; ! 433: values.graphics_exposures = (Bool) FALSE; ! 434: values.foreground = data->foreground; ! 435: values.background = w->core.background_pixel; ! 436: data->normgc = XtGetGC(w, valuemask, &values); ! 437: values.foreground = w->core.background_pixel; ! 438: values.background = data->foreground; ! 439: data->invgc = XtGetGC(w, valuemask, &values); ! 440: values.function = GXxor; ! 441: values.foreground = data->foreground ^ w->core.background_pixel; ! 442: values.background = 0; ! 443: data->xorgc = XtGetGC(w, valuemask, &values); ! 444: ! 445: wid = -1; ! 446: if ((!XGetFontProperty(font, XA_QUAD_WIDTH, &wid)) || wid <= 0) { ! 447: if (font->per_char && font->min_char_or_byte2 <= '0' && ! 448: font->max_char_or_byte2 >= '0') ! 449: wid = font->per_char['0' - font->min_char_or_byte2].width; ! 450: else ! 451: wid = font->max_bounds.width; ! 452: } ! 453: if (wid <= 0) wid = 1; ! 454: data->tabwidth = 8 * wid; ! 455: data->font = font; ! 456: /* data->insertCursorOn = CreateInsertCursor(XtDisplay(w), ! 457: data->normgc, XtisOn);*/ ! 458: /* data->insertCursorOff = CreateInsertCursor(XtDisplay(w), ! 459: data->normgc, XtisOff);*/ ! 460: data->insertCursorOn = CreateInsertCursor(XtDisplay(w), ! 461: data->xorgc, XtisOn); ! 462: data->laststate = XtisOff; ! 463: return(caddr_t) sink; ! 464: } ! 465: ! 466: void XtAsciiSinkDestroy (w) ! 467: Widget w; ! 468: { ! 469: XtTextSink *sink = ((TextWidget)w)->text.sink; ! 470: AsciiSinkData *data; ! 471: ! 472: data = (AsciiSinkData *) sink->data; ! 473: XtFree((char *) data); ! 474: XtFree((char *) sink); ! 475: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.