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