|
|
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.