1 /*
2  * A Scrollable Text Output Window
3  *
4  * David Harrison
5  * University of California,  Berkeley
6  * 1986
7  *
8  * The following is an implementation for a scrollable text output
9  * system.  It handles exposure events only (other interactions are
10  * under user control).  For scrolling,  a always present scroll bar
11  * is implemented.  It detects size changes and compensates accordingly.
12  */
13 
14 #include <X11/X.h>
15 #include <X11/Xlib.h>
16 #include <X11/X10.h>
17 #include <sys/types.h>
18 #include "scrollText.h"
19 
20 extern char *malloc();
21 extern char *realloc();
22 #define alloc(type)		(type *) malloc(sizeof(type))
23 #define numalloc(type, num)	(type *) malloc((unsigned) (num * sizeof(type)))
24 #define MAXINT		2147483647
25 
26 extern XAssocTable *XCreateAssocTable();
27 extern caddr_t XLookUpAssoc();
28 
29 static XAssocTable *textWindows = (XAssocTable *) 0;
30 
31 #define NOOPTION	-1	/* Option hasn't been set yet                */
32 #define NORMSCROLL	0	/* Smooth scroll on LineToTop and TopToHere  */
33 #define JUMPSCROLL	1	/* Jump scrolling on LineToTop and TopToHere */
34 
35 static int ScrollOption = NOOPTION;
36 
37 typedef char *Generic;
38 
39 #define DEFAULT_GC textInfo->fontGC[textInfo->curFont]
40 
41 #define BARSIZE		15
42 #define BARBORDER	1
43 #define MAXFONTS	8
44 #define INITBUFSIZE	1024
45 #define INITLINES	50
46 #define INITEXPARY	50
47 #define XPADDING	2
48 #define YPADDING	2
49 #define INTERLINE	5
50 #define INTERSPACE	1
51 #define CURSORWIDTH	2
52 #define EXPANDPERCENT	40
53 #define BUFSIZE		1024
54 #define CUROFFSET	1
55 #define MAXFOREIGN	250
56 #define NOINDEX		-1
57 
58 /* The wrap line indicator */
59 #define WRAPINDSIZE	7
60 #define STEMOFFSET	5
61 #define arrow_width 7
62 #define arrow_height 5
63 static char arrow_bits[] = {
64    0x24, 0x26, 0x3f, 0x06, 0x04};
65 
66 #define NEWLINE		'\n'
67 #define BACKSPACE	'\010'
68 #define NEWFONT		'\006'
69 #define LOWCHAR		'\040'
70 #define HIGHCHAR	'\176'
71 
72 #define CHARMASK	0x00ff	/* Character mask */
73 #define FONTMASK	0x0700	/* Character font */
74 #define FONTSHIFT	8	/* Shift amount   */
75 
76 #define WRAPFLAG	0x01	/* Line wrap flag */
77 
78 /*
79  * Lines are represented by a pointer into the overall array of
80  * 16-bit characters.  The lower eight bits is used to indicate the character
81  * (in ASCII),  and the next two bits are used to indicate the font
82  * the character should be drawn in.
83  */
84 
85 typedef struct txtLine {
86     int lineLength;		/* Current line length               */
87     int lineHeight;		/* Full height of line in pixels     */
88     int lineBaseLine;		/* Current baseline of the line      */
89     int lineWidth;		/* Drawing position at end of line   */
90     int lineText;		/* Offset into master buffer         */
91     int lineFlags;		/* Line wrap flag is here            */
92 };
93 
94 
95 /*
96  * For ExposeCopy events,  we queue up the redraw requests collapsing
97  * them into line redraw requests until the CopyExpose event arrives.
98  * The queue is represented as a dynamic array of the following
99  * structure:
100  */
101 
102 typedef struct expEvent {
103     int lineIndex;		/* Index of line to redraw  */
104     int ypos;			/* Drawing position of line */
105 };
106 
107 
108 /*
109  * The text buffer is represented using a dynamic counted array
110  * of 16-bit quantities. This array expands as needed.
111  * For the screen representation,  a dynamic counted array
112  * of line structures is used.  This array points into the
113  * text buffer to denote the start of each line and its parameters.
114  * The windows are configured as one overall window which contains
115  * the scroll bar as a sub-window along its right edge.  Thus,
116  * the text drawing space is actually w-BARSIZE.
117  */
118 
119 #define NOTATBOTTOM	0x01	/* Need to scroll to bottom before appending */
120 #define FONTNUMWAIT	0x02	/* Waiting for font number                   */
121 #define COPYEXPOSE	0x04	/* Need to process a copy expose event       */
122 #define SCREENWRONG	0x08	/* TxtJamStr has invalidated screen contents */
123 
124 typedef struct txtWin {
125     /* Basic text buffer */
126     int bufAlloc;		/* Allocated size of buffer           */
127     int bufSpot;		/* Current writing position in buffer */
128     short *mainBuffer;		/* Main buffer of text                */
129 
130     /* Line information */
131     int numLines;		/* Number of display lines in buffer */
132     int allocLines;		/* Number of lines allocated 	     */
133     struct txtLine **txtBuffer;	/* Dynamic array of lines    	     */
134 
135     /* Current Window display information */
136     Window mainWindow;		/* Text display window       */
137     Window scrollBar;		/* Subwindow for scroll bar  */
138     Pixmap arrowMap;		/* line wrap indicator       */
139     int bgPix, fgPix;		/* Background and cursor     */
140     GC CursorGC;		/* gc for the cursor         */
141     GC bgGC;			/* gc for erasing things     */
142     GC fontGC[MAXFONTS];	/* gc for doing fonts        */
143     XFontStruct theFonts[MAXFONTS];/* Display fonts          */
144     int  theColors[MAXFONTS];	/* foregrounds of the fonts  */
145     int  curFont;		/* current font for tracking */
146     int w, h;			/* Current size              */
147     int startLine;		/* Top line in display       */
148     int endLine;		/* Bottom line in display    */
149     int bottomSpace;		/* Space at bottom of screen */
150     int flagWord;		/* If non-zero,  not at end  */
151 
152     /* For handling ExposeCopy events */
153     int exposeSize;		/* Current size of array      */
154     int exposeAlloc;		/* Allocated size             */
155     struct expEvent **exposeAry;/* Array of line indices      */
156 
157     /* Drawing position information */
158     int curLine;		/* Current line in buffer    */
159     int curX;			/* Current horizontal positi */
160     int curY;			/* Current vertical drawing  */
161 };
162 
163 /* Flags for the various basic character handling functions */
164 
165 #define DODISP		0x01	/* Update the display  */
166 #define NONEWLINE	0x02	/* Dont append newline */
167 
168 
169 
InitLine(newLine)170 static int InitLine(newLine)
171 struct txtLine *newLine;	/* Newly created line structure */
172 /*
173  * This routine initializes a newly created line structure.
174  */
175 {
176     newLine->lineLength = 0;
177     newLine->lineHeight = 0;
178     newLine->lineBaseLine = 0;
179     newLine->lineWidth = XPADDING;
180     newLine->lineText = NOINDEX;
181     newLine->lineFlags = 0;
182     return 1;
183 }
184 
185 
186 
187 
TxtGrab(display,txtWin,program,mainFont,bg,fg,cur)188 int TxtGrab(display, txtWin, program, mainFont, bg, fg, cur)
189 Display *display;		/* display window is on  */
190 Window txtWin;			/* Window to take over as scrollable text    */
191 char *program;			/* Program name for Xdefaults                */
192 XFontStruct *mainFont;		/* Primary text font                         */
193 int bg, fg, cur;		/* Background, foreground, and cursor colors */
194 /*
195  * This routine takes control of 'txtWin' and makes it into a scrollable
196  * text output window.  It will create a sub-window for the scroll bar
197  * with a background of 'bg' and an bar with color 'fg'.  Both fixed width
198  * and variable width fonts are supported.  Additional fonts can be loaded
199  * using 'TxtAddFont'.  Returns 0 if there were problems,  non-zero if
200  * everything went ok.
201  */
202 {
203     struct txtWin *newWin;	/* Text package specific information */
204     XWindowAttributes winInfo;	/* Window information                */
205     int index;
206     XGCValues gc_val;
207 
208     if (textWindows == (XAssocTable *) 0) {
209 	textWindows = XCreateAssocTable(32);
210 	if (textWindows == (XAssocTable *) 0) return(0);
211     }
212     if (XGetWindowAttributes(display, txtWin, &winInfo) == 0) return 0;
213 
214     if (ScrollOption == NOOPTION) {
215 	/* Read to see if the user wants jump scrolling or not */
216 	if (XGetDefault(display, program, "JumpScroll")) {
217 	    ScrollOption = JUMPSCROLL;
218 	} else {
219 	    ScrollOption = NORMSCROLL;
220 	}
221     }
222 
223     /* Initialize local structure */
224     newWin = alloc(struct txtWin);
225 
226     /* Initialize arrow pixmap */
227     newWin->arrowMap = XCreatePixmapFromBitmapData(display, txtWin,
228 						   arrow_bits,
229 						   arrow_width, arrow_height,
230 						   cur, bg,
231 						   DisplayPlanes(display, 0));
232 
233     newWin->bufAlloc = INITBUFSIZE;
234     newWin->bufSpot = 0;
235     newWin->mainBuffer = numalloc(short, INITBUFSIZE);
236 
237     newWin->numLines = 1;
238     newWin->allocLines = INITLINES;
239     newWin->txtBuffer = numalloc(struct txtLine *, INITLINES);
240     for (index = 0;  index < INITLINES;  index++) {
241 	newWin->txtBuffer[index] = alloc(struct txtLine);
242 	InitLine(newWin->txtBuffer[index]);
243     }
244 
245     /* Window display information */
246     newWin->mainWindow = txtWin;
247     newWin->w = winInfo.width;
248     newWin->h = winInfo.height;
249     newWin->startLine = 0;
250     newWin->endLine = 0;
251     newWin->bottomSpace = winInfo.height
252       - YPADDING - mainFont->ascent - mainFont->descent - INTERLINE;
253     newWin->flagWord = 0;
254     newWin->bgPix = bg;
255     newWin->fgPix = fg;
256 
257     /* Scroll Bar Creation */
258     newWin->scrollBar = XCreateSimpleWindow(display, txtWin,
259 				      winInfo.width - BARSIZE,
260 				      0, BARSIZE - (2*BARBORDER),
261 				      winInfo.height - (2*BARBORDER),
262 				      BARBORDER,
263 				      fg, bg);
264     XSelectInput(display, newWin->scrollBar, ExposureMask|ButtonReleaseMask);
265     XMapRaised(display, newWin->scrollBar);
266 
267     /* Font and Color Initialization */
268     newWin->theFonts[0] = *mainFont;
269     newWin->theColors[0] = fg;
270     gc_val.function = GXcopy;
271     gc_val.plane_mask = AllPlanes;
272     gc_val.foreground = fg;
273     gc_val.background = bg;
274     gc_val.graphics_exposures = 1;
275     gc_val.font = mainFont->fid;
276     gc_val.line_width = 1;
277     gc_val.line_style = LineSolid;
278 
279     newWin->fontGC[0] = XCreateGC(display, txtWin,
280 				  GCFunction | GCPlaneMask |
281 				  GCForeground | GCBackground |
282 				  GCGraphicsExposures | GCFont,
283 				  &gc_val);
284 
285     gc_val.foreground = cur;
286     newWin->CursorGC = XCreateGC(display, txtWin,
287 				 GCFunction | GCPlaneMask |
288 				  GCForeground | GCBackground |
289 				  GCLineStyle | GCLineWidth,
290 				  &gc_val);
291 
292     gc_val.foreground = bg;
293     newWin->bgGC = XCreateGC(display, txtWin,
294 				  GCFunction | GCPlaneMask |
295 				  GCForeground | GCBackground |
296 				  GCGraphicsExposures | GCFont,
297 				  &gc_val);
298 
299 
300     for (index = 1;  index < MAXFONTS;  index++) {
301 	newWin->theFonts[index].fid = 0;
302 	newWin->fontGC[index] = 0;
303     }
304 
305 
306     /* Initialize size of first line */
307     newWin->txtBuffer[0]->lineHeight = newWin->theFonts[0].ascent +
308 	newWin->theFonts[0].descent;
309     newWin->txtBuffer[0]->lineText = 0;
310 
311     /* ExposeCopy array initialization */
312     newWin->exposeSize = 0;
313     newWin->exposeAlloc = INITEXPARY;
314     newWin->exposeAry = numalloc(struct expEvent *, INITEXPARY);
315     for (index = 0;  index < newWin->exposeAlloc;  index++)
316       newWin->exposeAry[index] = alloc(struct expEvent);
317     /* Put plus infinity in last slot for sorting purposes */
318     newWin->exposeAry[0]->lineIndex = MAXINT;
319 
320     /* Drawing Position Information */
321     newWin->curLine = 0;
322     newWin->curX = 0;
323     newWin->curY = YPADDING + mainFont->ascent + mainFont->descent;
324 
325     /* Attach it to both windows */
326     XMakeAssoc(display, textWindows, (XID) txtWin, (caddr_t) newWin);
327     XMakeAssoc(display, textWindows, (XID) newWin->scrollBar, (caddr_t) newWin);
328     return 1;
329 }
330 
331 
TxtRelease(display,w)332 int TxtRelease(display, w)
333 Display *display;
334 Window w;			/* Window to release */
335 /*
336  * This routine releases all resources associated with the
337  * specified window which are consumed by the text
338  * window package. This includes the entire text buffer,  line start
339  * array,  and the scroll bar window.  However,  the window
340  * itself is NOT destroyed.  The routine will return zero if
341  * the window is not owned by the text window package.
342  */
343 {
344     struct txtWin *textInfo;
345     int index;
346 
347     if ((textInfo = (struct txtWin *) XLookUpAssoc(display,
348 						 textWindows, (XID) w)) == 0)
349       return 0;
350 
351     for (index = 0; index < MAXFONTS; index++)
352 	if (textInfo->fontGC[index] != 0)
353 	    XFreeGC(display, textInfo->fontGC[index]);
354 
355     free((Generic) textInfo->mainBuffer);
356     for (index = 0;  index < textInfo->numLines;  index++) {
357 	free((Generic) textInfo->txtBuffer[index]);
358     }
359     free((Generic) textInfo->txtBuffer);
360     XDestroyWindow(display, textInfo->scrollBar);
361     for (index = 0;  index < textInfo->exposeSize;  index++) {
362 	free((Generic) textInfo->exposeAry[index]);
363     }
364     free((Generic) textInfo->exposeAry);
365     XDeleteAssoc(display, textWindows, (XID) w);
366     free((Generic) textInfo);
367     return 1;
368 }
369 
370 
371 
RecompBuffer(textInfo)372 static int RecompBuffer(textInfo)
373 struct txtWin *textInfo;	/* Text window information */
374 /*
375  * This routine recomputes all line breaks in a buffer after
376  * a change in window size or font.  This is done by throwing
377  * away the old line start array and recomputing it.  Although
378  * a lot of this work is also done elsewhere,  it has been included
379  * inline here for efficiency.
380  */
381 {
382     int startPos, endSize, linenum;
383     register int index, chsize, curfont;
384     register short *bufptr;
385     register XFontStruct *fontptr;
386     register struct txtLine *lineptr;
387     char theChar;
388 
389     /* Record the old position so we can come back to it */
390     for (startPos = textInfo->txtBuffer[textInfo->startLine]->lineText;
391 	 (startPos > 0) && (textInfo->mainBuffer[startPos] != '\n');
392 	 startPos--)
393       /* null loop body */;
394 
395     /* Clear out the old line start array */
396     for (index = 0;  index < textInfo->numLines;  index++) {
397 	InitLine(textInfo->txtBuffer[index]);
398     }
399 
400     /* Initialize first line */
401     textInfo->txtBuffer[0]->lineHeight =
402 	textInfo->theFonts[0].ascent + textInfo->theFonts[0].descent;
403     textInfo->txtBuffer[0]->lineText = 0;
404 
405     /* Process the text back into lines */
406     endSize = textInfo->w - BARSIZE - WRAPINDSIZE;
407     bufptr = textInfo->mainBuffer;
408     lineptr = textInfo->txtBuffer[0];
409     linenum = 0;
410     fontptr = &(textInfo->theFonts[0]);
411     curfont = 0;
412     for (index = 0;  index < textInfo->bufSpot;  index++) {
413 	theChar = bufptr[index] & CHARMASK;
414 
415 	if ((bufptr[index] & FONTMASK) != curfont) {
416 	    int newFontNum, heightDiff;
417 
418 	    /* Switch fonts */
419 	    newFontNum = (bufptr[index] & FONTMASK) >> FONTSHIFT;
420 	    if (textInfo->theFonts[newFontNum].fid != 0) {
421 		/* Valid font */
422 		curfont = bufptr[index] & FONTMASK;
423 		fontptr = &(textInfo->theFonts[newFontNum]);
424 		heightDiff = (fontptr->ascent + fontptr->descent) -
425 		    lineptr->lineHeight;
426 		if (heightDiff < 0) heightDiff = 0;
427 		lineptr->lineHeight += heightDiff;
428 	    }
429 	}
430 	if (theChar == '\n') {
431 	    /* Handle new line */
432 	    if (linenum >= textInfo->allocLines-1)
433 	      /* Expand number of lines */
434 	      ExpandLines(textInfo);
435 	    linenum++;
436 	    lineptr = textInfo->txtBuffer[linenum];
437 	    /* Initialize next line */
438 	    lineptr->lineHeight = fontptr->ascent + fontptr->descent;
439 	    lineptr->lineText = index+1;
440 	    /* Check to see if its the starting line */
441 	    if (index == startPos) textInfo->startLine = linenum;
442 	} else {
443 	    /* Handle normal character */
444 	    chsize = CharSize(textInfo, linenum, index);
445 	    if (lineptr->lineWidth + chsize > endSize) {
446 		/* Handle line wrap */
447 		lineptr->lineFlags |= WRAPFLAG;
448 		if (linenum >= textInfo->allocLines-1)
449 		  /* Expand number of lines */
450 		  ExpandLines(textInfo);
451 		linenum++;
452 		lineptr = textInfo->txtBuffer[linenum];
453 		/* Initialize next line */
454 		lineptr->lineHeight = fontptr->ascent + fontptr->descent;
455 		lineptr->lineText = index;
456 		lineptr->lineLength = 1;
457 		lineptr->lineWidth += chsize;
458 	    } else {
459 		/* Handle normal addition of character */
460 		lineptr->lineLength += 1;
461 		lineptr->lineWidth += chsize;
462 	    }
463 	}
464     }
465     /* We now have a valid line array.  Let's clean up some other fields. */
466     textInfo->numLines = linenum+1;
467     if (startPos == 0) {
468 	textInfo->startLine = 0;
469     }
470     textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
471     textInfo->curLine = linenum;
472     /* Check to see if we are at the bottom */
473     if (textInfo->endLine >= textInfo->numLines-1) {
474 	textInfo->curY = textInfo->h - textInfo->bottomSpace -
475 	  lineptr->lineHeight;
476 	textInfo->flagWord &= (~NOTATBOTTOM);
477     } else {
478 	textInfo->flagWord |= NOTATBOTTOM;
479     }
480     return 1;
481 }
482 
483 
484 
485 
TxtAddFont(display,textWin,fontNumber,newFont,newColor)486 int TxtAddFont(display, textWin, fontNumber, newFont, newColor)
487 Display *display;
488 Window textWin;			/* Scrollable text window  */
489 int fontNumber;			/* Place to add font (0-7) */
490 XFontStruct *newFont;		/* Font to add             */
491 int newColor;			/* Color of font           */
492 /*
493  * This routine loads a new font so that it can be used in a previously
494  * created text window.  There are eight font slots numbered 0 through 7.
495  * If there is already a font in the specified slot,  it will be replaced
496  * and an automatic redraw of the window will take place.  See TxtWriteStr
497  * for details on using alternate fonts.  The color specifies the foreground
498  * color of the text.  The default foreground color is used if this
499  * parameter is TXT_NO_COLOR.  Returns a non-zero value if
500  * everything went well.
501  */
502 {
503     struct txtWin *textInfo;
504     int redrawFlag;
505     XGCValues gc_val;
506 
507     if ((fontNumber < 0) || (fontNumber >= MAXFONTS)) return 0;
508     if ((textInfo = (struct txtWin *)
509 	 XLookUpAssoc(display, textWindows, (XID) textWin)) == 0)
510       return 0;
511     if (newColor == TXT_NO_COLOR) {
512 	newColor = textInfo->fgPix;
513     }
514 
515     gc_val.font = newFont->fid;
516     gc_val.foreground = newColor;
517     gc_val.background = textInfo->bgPix;
518     gc_val.plane_mask = AllPlanes;
519     gc_val.graphics_exposures = 1;
520     gc_val.function = GXcopy;
521 
522     if (textInfo->fontGC[fontNumber] != 0)
523     {
524 	XChangeGC(display, textInfo->fontGC[fontNumber],
525 		  GCFont | GCForeground, &gc_val);
526     }
527     else
528 	textInfo->fontGC[fontNumber] = XCreateGC(display, textWin,
529 						 GCFont |
530 						 GCForeground |
531 						 GCBackground |
532 						 GCFunction |
533 						 GCPlaneMask |
534 						 GCGraphicsExposures,
535 						 &gc_val);
536 
537 
538     redrawFlag = (textInfo->theFonts[fontNumber].fid != 0) &&
539       (((newFont) && (newFont->fid != textInfo->theFonts[fontNumber].fid)) ||
540        (newColor != textInfo->theColors[fontNumber]));
541     if (newFont) {
542 	textInfo->theFonts[fontNumber] = *newFont;
543     }
544     textInfo->theColors[fontNumber] = newColor;
545 
546     if (redrawFlag) {
547 	RecompBuffer(textInfo);
548 	XClearWindow(display, textWin);
549 	TxtRepaint(display, textWin);
550     }
551     return 1;
552 }
553 
554 
555 
TxtWinP(display,w)556 int TxtWinP(display, w)
557 Display *display;
558 Window w;
559 /*
560  * Returns a non-zero value if the window has been previously grabbed
561  * using TxtGrab and 0 if it has not.
562  */
563 {
564     if (XLookUpAssoc(display, textWindows, (XID) w))
565       return(1);
566     else return(0);
567 }
568 
569 
570 
FindEndLine(textInfo,botSpace)571 static int FindEndLine(textInfo, botSpace)
572 struct txtWin *textInfo;
573 int *botSpace;
574 /*
575  * Given the starting line in 'textInfo->startLine',  this routine
576  * determines the index of the last line that can be drawn given the
577  * current size of the screen.  If there are not enough lines to
578  * fill the screen,  the index of the last line will be returned.
579  * The amount of empty bottom space is returned in 'botSpace'.
580  */
581 {
582     int index, height, lineHeight;
583 
584     height = YPADDING;
585     index = textInfo->startLine;
586     while (index < textInfo->numLines) {
587 	lineHeight = textInfo->txtBuffer[index]->lineHeight + INTERLINE;
588 	if (height + lineHeight > textInfo->h) break;
589 	height += lineHeight;
590 	index++;
591     }
592     if (botSpace) {
593 	*botSpace = textInfo->h - height;
594     }
595     return index - 1;
596 }
597 
598 
599 
UpdateScroll(display,textInfo)600 static int UpdateScroll(display, textInfo)
601 Display *display;
602 struct txtWin *textInfo;	/* Text window information */
603 /*
604  * This routine computes the current extent of the scroll bar
605  * indicator and repaints the bar with the correct information.
606  */
607 {
608     int top, bottom;
609 
610     if (textInfo->numLines > 1) {
611 	top = textInfo->startLine * (textInfo->h - 2*BARBORDER) /
612 	  (textInfo->numLines - 1);
613 	bottom = textInfo->endLine * (textInfo->h - 2*BARBORDER) /
614 	  (textInfo->numLines - 1);
615     } else {
616 	top = 0;
617 	bottom = textInfo->h - (2*BARBORDER);
618     }
619 
620     /* Draw it - make sure there is a little padding */
621     if (top == 0) top++;
622     if (bottom == textInfo->h-(2*BARBORDER)) bottom--;
623 
624     XFillRectangle(display, textInfo->scrollBar,
625 		   textInfo->bgGC,
626 		   0, 0, BARSIZE, top-1);
627     XFillRectangle(display, textInfo->scrollBar,
628 		   DEFAULT_GC, top, BARSIZE - (2*BARBORDER) - 2,
629 		   bottom - top);
630     XFillRectangle(display, textInfo->scrollBar, DEFAULT_GC,
631 		   0, bottom+1, BARSIZE,
632 		   textInfo->h - (2 * BARBORDER) - bottom);
633 
634     return 1;
635 }
636 
637 
638 
639 
TxtClear(display,w)640 int TxtClear(display, w)
641 Display *display;
642 Window w;
643 /*
644  * This routine clears a scrollable text window.  It resets the current
645  * writing position to the upper left hand corner of the screen.
646  * NOTE:  THIS ALSO CLEARS THE CONTENTS OF THE TEXT WINDOW BUFFER AND
647  * RESETS THE SCROLL BAR.  Returns 0 if the window is not a text window.
648  * This should be used *instead* of XClear.
649  */
650 {
651     struct txtWin *textInfo;
652     int index;
653 
654     if ((textInfo = (struct txtWin *) XLookUpAssoc(display, textWindows, (XID) w)) == 0)
655       return 0;
656 
657     /* Zero out the arrays */
658     textInfo->bufSpot = 0;
659     for (index = 0;  index < textInfo->numLines;  index++) {
660 	InitLine(textInfo->txtBuffer[index]);
661     }
662     textInfo->txtBuffer[0]->lineHeight =
663       textInfo->theFonts[textInfo->curFont].ascent +
664 	  textInfo->theFonts[textInfo->curFont].descent;
665 
666     textInfo->numLines = 1;
667     textInfo->startLine = 0;
668     textInfo->endLine = 0;
669     textInfo->curLine = 0;
670     textInfo->curX = 0;
671     textInfo->curY = YPADDING + textInfo->theFonts[textInfo->curFont].ascent
672 	+ textInfo->theFonts[textInfo->curFont].descent;
673 
674     textInfo->bottomSpace = textInfo->h - YPADDING -
675       textInfo->theFonts[textInfo->curFont].ascent - INTERLINE -
676 	  textInfo->theFonts[textInfo->curFont].descent;
677     /* Actually clear the window */
678     XClearWindow(display, w);
679 
680     /* Draw the current cursor */
681     XFillRectangle(display, w, textInfo->CursorGC,
682 		   XPADDING + CUROFFSET, textInfo->curY,
683 		   CURSORWIDTH,
684 		   textInfo->theFonts[textInfo->curFont].ascent +
685 		   textInfo->theFonts[textInfo->curFont].descent);
686 
687     /* Update the scroll bar */
688     UpdateScroll(display, textInfo);
689     return 1;
690 }
691 
692 
WarpToBottom(display,textInfo)693 static int WarpToBottom(display, textInfo)
694 Display *display;
695 struct txtWin *textInfo;	/* Text Information */
696 /*
697  * This routine causes the specified text window to display its
698  * last screen of information.   It updates the scroll bar
699  * to the appropriate spot.  The implementation scans backward
700  * through the buffer to find an appropriate starting spot for
701  * the window.
702  */
703 {
704     int index, height, lineHeight;
705 
706     index = textInfo->numLines-1;
707     height = 0;
708     while (index >= 0) {
709 	lineHeight = textInfo->txtBuffer[index]->lineHeight + INTERLINE;
710 	if (height + lineHeight > textInfo->h) break;
711 	height += lineHeight;
712 	index--;
713     }
714     textInfo->startLine = index + 1;
715     textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
716     textInfo->curY = textInfo->h - textInfo->bottomSpace -
717       textInfo->txtBuffer[textInfo->endLine]->lineHeight;
718     XClearWindow(display, textInfo->mainWindow);
719     TxtRepaint(display, textInfo->mainWindow);
720     return 1;
721 }
722 
723 
724 
UpdateExposures(display,textInfo)725 static int UpdateExposures(display, textInfo)
726 Display *display;
727 struct txtWin *textInfo;	/* Text window information */
728 /*
729  * Before a new scrolling action occurs,  the text window package
730  * must handle all COPYEXPOSE events generated by the last scrolling
731  * action.  This routine is called to do this.  Foreign events (those
732  * not handled by TxtFilter) are queued up and replaced on the queue
733  * after the processing of the exposure events is complete.
734  */
735 {
736 #if 0
737     XEvent foreignQueue[MAXFOREIGN];
738     int index, lastItem = 0;
739 
740     while (textInfo->flagWord & COPYEXPOSE) {
741 	XNextEvent(display, &(foreignQueue[lastItem]));
742 	if (!TxtFilter(display, &(foreignQueue[lastItem])))
743 	  lastItem++;
744 	if (lastItem >= MAXFOREIGN) {
745 	    printf("Too many foreign events to queue!\n");
746 	    textInfo->flagWord &= (~COPYEXPOSE);
747 	}
748     }
749     for (index = 0;  index < lastItem;  index++) {
750 	XPutBackEvent(display, &(foreignQueue[index]));
751     }
752 #endif
753     return 1;
754 }
755 
756 
ScrollDown(display,textInfo)757 static int ScrollDown(display,textInfo)
758 Display *display;
759 struct txtWin *textInfo;	/* Text window information */
760 /*
761  * This routine scrolls the indicated text window down by one
762  * line.  The line below the current line must exist.  The window
763  * is scrolled so that the line below the last line is fully
764  * displayed.  This may cause many lines to scroll off the top.
765  * Scrolling is done using XCopyArea.  The exposure events should
766  * be caught using ExposeCopy.
767  */
768 {
769     int lineSum, index, targetSpace, freeSpace, updateFlag;
770 
771     lineSum = 0;
772     if (textInfo->endLine + 1 >= textInfo->numLines) return 0;
773     targetSpace = textInfo->txtBuffer[textInfo->endLine+1]->lineHeight +
774       INTERLINE;
775     if (textInfo->bottomSpace < targetSpace) {
776 	index = textInfo->startLine;
777 	while (index < textInfo->endLine) {
778 	    lineSum += (textInfo->txtBuffer[index]->lineHeight + INTERLINE);
779 	    if (textInfo->bottomSpace + lineSum >= targetSpace) break;
780 	    index++;
781 	}
782 
783 	/* Must move upward by 'lineSum' pixels */
784 	XCopyArea(display, textInfo->mainWindow, textInfo->mainWindow,
785 		  DEFAULT_GC, 0, lineSum,
786 		  textInfo->w - BARSIZE, textInfo->h,
787 		  0, 0);
788 
789 	textInfo->flagWord |= COPYEXPOSE;
790 	/* Repair the damage to the structures */
791 	textInfo->startLine = index + 1;
792 	updateFlag = 1;
793     } else {
794 	updateFlag = 0;
795     }
796     /* More lines might be able to fit.  Let's check. */
797     freeSpace = textInfo->bottomSpace + lineSum - targetSpace;
798     index = textInfo->endLine + 1;
799     while (index < textInfo->numLines-1) {
800 	if (freeSpace - textInfo->txtBuffer[index+1]->lineHeight - INTERLINE < 0)
801 	  break;
802 	freeSpace -= (textInfo->txtBuffer[index+1]->lineHeight + INTERLINE);
803 	index++;
804     }
805     textInfo->endLine = index;
806     textInfo->bottomSpace = freeSpace;
807     if (updateFlag) {
808 	UpdateExposures(display, textInfo);
809     }
810     UpdateScroll(display, textInfo);
811     return 1;
812 }
813 
814 
815 
816 
ExpandLines(textInfo)817 static int ExpandLines(textInfo)
818 struct txtWin *textInfo;	/* Text Information */
819 /*
820  * This routine allocates and initializes additional space in
821  * the line start array (txtBuffer).  The new space
822  * is allocated using realloc.  The expansion factor is a percentage
823  * given by EXPANDPERCENT.
824  */
825 {
826     int newSize, index;
827 
828     newSize = textInfo->allocLines;
829     newSize += (newSize * EXPANDPERCENT) / 100;
830 
831     textInfo->txtBuffer = (struct txtLine **)
832       realloc((char *) textInfo->txtBuffer,
833 	      (unsigned) (newSize * sizeof(struct txtLine *)));
834     for (index = textInfo->allocLines;  index < newSize;  index++) {
835 	textInfo->txtBuffer[index] = alloc(struct txtLine);
836 	InitLine(textInfo->txtBuffer[index]);
837     }
838     textInfo->allocLines = newSize;
839     return 1;
840 }
841 
ExpandBuffer(textInfo)842 static int ExpandBuffer(textInfo)
843 struct txtWin *textInfo;	/* Text information */
844 /*
845  * Expands the basic character buffer using realloc.  The expansion
846  * factor is a percentage given by EXPANDPERCENT.
847  */
848 {
849     int newSize;
850 
851     newSize = textInfo->bufAlloc + (textInfo->bufAlloc * EXPANDPERCENT) / 100;
852     textInfo->mainBuffer = (short *)
853       realloc((char *) textInfo->mainBuffer, (unsigned) newSize * sizeof(short));
854     textInfo->bufAlloc = newSize;
855     return 1;
856 }
857 
858 
859 
HandleNewLine(display,textInfo,flagWord)860 static int HandleNewLine(display, textInfo, flagWord)
861 Display *display;
862 struct txtWin *textInfo;	/* Text Information            */
863 int flagWord;			/* DODISP or NONEWLINE or both */
864 /*
865  * This routine initializes the next line for drawing by setting
866  * its height to the current font height,  scrolls the screen down
867  * one line,  and updates the current drawing position to the
868  * left edge of the newly cleared line.  If DODISP is specified,
869  * the screen will be updated (otherwise not).  If NONEWLINE is
870  * specified,  no newline character will be added to the text buffer
871  * (this is for line wrap).
872  */
873 {
874     struct txtLine *curLine, *nextLine;
875 
876     /* Check to see if a new line must be allocated */
877     if (textInfo->curLine >= textInfo->allocLines-1)
878       /* Expand the number of lines */
879       ExpandLines(textInfo);
880     textInfo->numLines += 1;
881 
882     /* Then we initialize the next line */
883     nextLine = textInfo->txtBuffer[textInfo->numLines-1];
884     nextLine->lineHeight =
885 	textInfo->theFonts[textInfo->curFont].ascent +
886 	    textInfo->theFonts[textInfo->curFont].descent;
887 
888     curLine = textInfo->txtBuffer[textInfo->curLine];
889     if (flagWord & DODISP) {
890 	/* Scroll down a line if required */
891 	if ((textInfo->curY + curLine->lineHeight +
892 	     nextLine->lineHeight + (INTERLINE * 2)) > textInfo->h)
893 	  {
894 	      ScrollDown(display, textInfo);
895 	  }
896 	else
897 	  {
898 	      /* Update the bottom space appropriately */
899 	      textInfo->bottomSpace -= (nextLine->lineHeight + INTERLINE);
900 	      textInfo->endLine += 1;
901 	  }
902 	/* Update drawing position */
903 	textInfo->curY = textInfo->h -
904 	  (textInfo->bottomSpace  + nextLine->lineHeight);
905     }
906 
907     /* Move down a line */
908     textInfo->curLine += 1;
909     if (!(flagWord & NONEWLINE)) {
910 	/* Append end-of-line to text buffer */
911 	if (textInfo->bufSpot >= textInfo->bufAlloc) {
912 	    /* Allocate more space in main text buffer */
913 	    ExpandBuffer(textInfo);
914 	}
915 	textInfo->mainBuffer[(textInfo->bufSpot)++] =
916 	  (textInfo->curFont << FONTSHIFT) | '\n';
917     }
918     nextLine->lineText = textInfo->bufSpot;
919     textInfo->curX = 0;
920     return 1;
921 }
922 
923 
924 
CharSize(textInfo,lineNum,charNum)925 static int CharSize(textInfo, lineNum, charNum)
926 struct txtWin *textInfo;	/* Current Text Information */
927 int lineNum;			/* Line in buffer           */
928 int charNum;			/* Character in line        */
929 /*
930  * This routine determines the size of the specified character.
931  * It takes in account the font of the character and whether its
932  * fixed or variable.  The size includes INTERSPACE spacing between
933  * the characters.
934  */
935 {
936     register XFontStruct *charFont;
937     register short *theLine;
938     register short theChar;
939 
940     theLine = &(textInfo->mainBuffer[textInfo->txtBuffer[lineNum]->lineText]);
941     theChar = theLine[charNum] & CHARMASK;
942     charFont = &(textInfo->theFonts[(theChar & FONTMASK) >> FONTSHIFT]);
943     if (theChar <= charFont->min_char_or_byte2 ||
944 	theChar >= charFont->max_char_or_byte2 ||
945 	charFont->per_char == 0)
946 	return  charFont->max_bounds.width + 1;
947     else
948 	return charFont->per_char[theChar].width + 1;
949 }
950 
951 
952 
953 
954 
HandleBackspace(display,textInfo,flagWord)955 static int HandleBackspace(display, textInfo, flagWord)
956 Display *display;
957 struct txtWin *textInfo;	/* Text Information  */
958 int flagWord;			/* DODISP or nothing */
959 /*
960  * This routine handles a backspace found in the input stream.  The
961  * character before the current writing position will be erased and
962  * the drawing position will move back one character.  If the writing
963  * position is at the left margin,  the drawing position will move
964  * up to the previous line.  If it is a line that has been wrapped,
965  * the character at the end of the previous line will be erased.
966  */
967 {
968     struct txtLine *thisLine, *prevLine;
969     int chSize;
970 
971     thisLine = textInfo->txtBuffer[textInfo->curLine];
972     /* First,  determine whether we need to go back a line */
973     if (thisLine->lineLength == 0) {
974 	/* Bleep if at top of buffer */
975 	if (textInfo->curLine == 0) {
976 	    XBell(display, 50);
977 	    return 0;
978 	}
979 
980 	/* See if we have to scroll in the other direction */
981 	if ((flagWord & DODISP) && (textInfo->curY <= YPADDING)) {
982 	    /* This will display the last lines of the buffer */
983 	    WarpToBottom(display, textInfo);
984 	}
985 
986 	/* Set drawing position at end of previous line */
987 	textInfo->curLine -= 1;
988 	prevLine = textInfo->txtBuffer[textInfo->curLine];
989 	textInfo->numLines -= 1;
990 	if (flagWord & DODISP) {
991 	    textInfo->curY -= (prevLine->lineHeight + INTERLINE);
992 	    textInfo->bottomSpace += (thisLine->lineHeight + INTERLINE);
993 	    textInfo->endLine -= 1;
994 	}
995 
996 	/* We are unlinewrapping if the previous line has flag set */
997 	if (prevLine->lineFlags & WRAPFLAG) {
998 	    /* Get rid of line wrap indicator */
999 	    if (flagWord & DODISP) {
1000 		XFillRectangle(display, textInfo->mainWindow,
1001 			       textInfo->bgGC,
1002 			       textInfo->w - BARSIZE - WRAPINDSIZE,
1003 			       textInfo->curY,  WRAPINDSIZE,
1004 			       prevLine->lineHeight);
1005 	    }
1006 	    prevLine->lineFlags &= (~WRAPFLAG);
1007 	    /* Call recursively to wipe out the ending character */
1008 	    HandleBackspace(display, textInfo, flagWord);
1009 	} else {
1010 	    /* Delete the end-of-line in the primary buffer */
1011 	    textInfo->bufSpot -= 1;
1012 	}
1013     } else {
1014 	/* Normal deletion of character */
1015 	chSize =
1016 	  CharSize(textInfo, textInfo->curLine,
1017 		   textInfo->txtBuffer[textInfo->curLine]->lineLength - 1);
1018 	/* Move back appropriate amount and wipe it out */
1019 	thisLine->lineWidth -= chSize;
1020 	if (flagWord & DODISP) {
1021 	    XFillRectangle(display, textInfo->mainWindow,
1022 			   textInfo->bgGC,
1023 			   thisLine->lineWidth, textInfo->curY,
1024 			   chSize, thisLine->lineHeight);
1025 	}
1026 	/* Delete from buffer */
1027 	textInfo->txtBuffer[textInfo->curLine]->lineLength -= 1;
1028 	textInfo->bufSpot -= 1;
1029     }
1030     return 1;
1031 }
1032 
1033 
1034 
DrawLineWrap(display,win,x,y,h,col)1035 static int DrawLineWrap(display, win, x, y, h, col)
1036 Display *display;
1037 Window win;			/* What window to draw it in     */
1038 int x, y;			/* Position of upper left corner */
1039 int h;				/* Height of indicator           */
1040 int col;			/* Color of indicator            */
1041 /*
1042  * This routine draws a line wrap indicator at the end of a line.
1043  * Visually,  it is an arrow of the specified height directly against
1044  * the scroll bar border.  The bitmap used for the arrow is stored
1045  * in 'arrowMap' with size 'arrow_width' and 'arrow_height'.
1046  */
1047 {
1048     struct txtWin *textInfo;
1049 
1050     textInfo = (struct txtWin *)XLookUpAssoc(display, textWindows,
1051 					     (XID) win);
1052 
1053     /* First,  draw the arrow */
1054     XCopyArea(display, textInfo->arrowMap, textInfo->mainWindow,
1055 	       textInfo->CursorGC,
1056 	       0, 0, arrow_width, arrow_height,
1057 	       x, y + h - arrow_height, 1);
1058 
1059     /* Then draw the stem */
1060     XDrawLine(display, textInfo->mainWindow, textInfo->CursorGC,
1061 	      x + STEMOFFSET, y,
1062 	      x + STEMOFFSET, y + h - arrow_height);
1063     return 1;
1064 }
1065 
1066 
1067 
1068 
DrawLine(display,textInfo,lineIndex,ypos)1069 static int DrawLine(display, textInfo, lineIndex, ypos)
1070 Display *display;
1071 struct txtWin *textInfo;	/* Text window information   */
1072 int lineIndex;			/* Index of line to draw     */
1073 int ypos;			/* Y position for line       */
1074 /*
1075  * This routine destructively draws the indicated line in the
1076  * indicated window at the indicated position.  It does not
1077  * clear to end of line however.  It draws a line wrap indicator
1078  * if needed but does not draw a cursor.
1079  */
1080 {
1081     int index, startPos, curFont, theColor, curX, saveX, fontIndex;
1082     struct txtLine *someLine;
1083     char lineBuffer[BUFSIZE], *glyph;
1084     short *linePointer;
1085     XFontStruct *theFont;
1086     XGCValues gc;
1087 
1088     /* First,  we draw the text */
1089     index = 0;
1090     curX = XPADDING;
1091     someLine = textInfo->txtBuffer[lineIndex];
1092     linePointer = &(textInfo->mainBuffer[someLine->lineText]);
1093     while (index < someLine->lineLength) {
1094 	startPos = index;
1095 	saveX = curX;
1096 	curFont = linePointer[index] & FONTMASK;
1097 	fontIndex = curFont >> FONTSHIFT;
1098 	theFont = &(textInfo->theFonts[fontIndex]);
1099 	theColor = textInfo->theColors[fontIndex];
1100 	glyph = &(lineBuffer[0]);
1101 	while ((index < someLine->lineLength) &&
1102 	       ((linePointer[index] & FONTMASK) == curFont))
1103 	{
1104 	    *glyph = linePointer[index] & CHARMASK;
1105 	    index++;
1106 	    curX += CharSize(textInfo, lineIndex, index);
1107 	    glyph++;
1108 	}
1109 
1110 	/* Flush out the glyphs */
1111 	XFillRectangle(display, textInfo->mainWindow,
1112 		       textInfo->bgGC,
1113 		       saveX, ypos,
1114 		   textInfo->w - BARSIZE,
1115 		   someLine->lineHeight + YPADDING + INTERLINE);
1116 
1117 	XDrawString(display, textInfo->mainWindow,
1118 		    textInfo->fontGC[fontIndex],
1119 		    saveX, ypos,
1120 		    lineBuffer, someLine->lineLength);
1121     }
1122     /* Then the line wrap indicator (if needed) */
1123     if (someLine->lineFlags & WRAPFLAG) {
1124 	DrawLineWrap(display, textInfo->mainWindow,
1125 		     textInfo->w - BARSIZE - WRAPINDSIZE,
1126 		     ypos, someLine->lineHeight,
1127 		     textInfo->fgPix);
1128     }
1129     return 1;
1130 }
1131 
1132 
1133 
1134 
HandleNewFont(display,fontNum,textInfo,flagWord)1135 static int HandleNewFont(display, fontNum, textInfo, flagWord)
1136 Display *display;
1137 int fontNum;			/* Font number       */
1138 struct txtWin *textInfo;	/* Text information  */
1139 int flagWord;			/* DODISP or nothing */
1140 /*
1141  * This routine handles a new font request.  These requests take
1142  * the form "^F<digit>".  The parsing is done in TxtWriteStr.
1143  * This routine is called only if the form is valid.  It may return
1144  * a failure (0 status) if the requested font is not loaded.
1145  * If the new font is larger than any of the current
1146  * fonts on the line,  it will change the line height and redisplay
1147  * the line.
1148  */
1149 {
1150     struct txtLine *thisLine;
1151     int heightDiff, baseDiff, redrawFlag;
1152 
1153     if (textInfo->theFonts[fontNum].fid == 0) {
1154 	return 0;
1155     } else {
1156 	thisLine = textInfo->txtBuffer[textInfo->curLine];
1157 	textInfo->curFont = fontNum;
1158 	redrawFlag = 0;
1159 	heightDiff = textInfo->theFonts[fontNum].ascent +
1160 	    textInfo->theFonts[fontNum].descent -
1161 		thisLine->lineHeight;
1162 
1163 	if (heightDiff > 0) {
1164 	    redrawFlag = 1;
1165 	} else {
1166 	    heightDiff = 0;
1167 	}
1168 
1169 	if (redrawFlag) {
1170 	    if (flagWord & DODISP) {
1171 		/* Clear current line */
1172 		XFillRectangle(display, textInfo->mainWindow,
1173 			       textInfo->bgGC,
1174 			       0, textInfo->curY, textInfo->w,
1175 			       thisLine->lineHeight);
1176 
1177 		/* Check to see if it requires scrolling */
1178 		if ((textInfo->curY + thisLine->lineHeight + heightDiff +
1179 		     INTERLINE) > textInfo->h)
1180 		  {
1181 		      /*
1182 		       * General approach:  "unscroll" the last line up
1183 		       * and then call ScrollDown to do the right thing.
1184 		       */
1185 		      textInfo->endLine -= 1;
1186 		      textInfo->bottomSpace += thisLine->lineHeight +
1187 			  INTERLINE;
1188 
1189 		      XFillRectangle(display, textInfo->mainWindow,
1190 				     textInfo->bgGC,
1191 				     0, textInfo->h - textInfo->bottomSpace,
1192 				     textInfo->w, textInfo->bottomSpace);
1193 
1194 		      thisLine->lineHeight += heightDiff;
1195 		      ScrollDown(display, textInfo);
1196 		      textInfo->curY = textInfo->h -
1197 			(textInfo->bottomSpace + INTERLINE +
1198 			 thisLine->lineHeight);
1199 		  }
1200 		else
1201 		  {
1202 		      /* Just update bottom space */
1203 		      textInfo->bottomSpace -= heightDiff;
1204 		      thisLine->lineHeight += heightDiff;
1205 		  }
1206 		/* Redraw the current line */
1207 		DrawLine(display, textInfo, textInfo->curLine, textInfo->curY);
1208 	    } else {
1209 		/* Just update line height */
1210 		thisLine->lineHeight += heightDiff;
1211 	    }
1212 	}
1213 	return 1;
1214     }
1215 }
1216 
1217 
1218 
TxtWriteStr(display,w,str)1219 int TxtWriteStr(display, w, str)
1220 Display *display;
1221 Window w;			/* Text window            */
1222 register char *str;		/* 0 terminated string */
1223 /*
1224  * This routine writes a string to the specified text window.
1225  * The following notes apply:
1226  *   - Text is always appended to the end of the text buffer.
1227  *   - If the scroll bar is positioned such that the end of the
1228  *     text is not visible,  an automatic scroll to the bottom
1229  *     will be done before the appending of text.
1230  *   - Non-printable ASCII characters are not displayed.
1231  *   - The '\n' character causes the current text position to
1232  *     advance one line and start at the left.
1233  *   - Tabs are not supported.
1234  *   - Lines too long for the screen will be wrapped and a line wrap
1235  *     indication will be drawn.
1236  *   - Backspace clears the previous character.  It will do the right
1237  *     thing if asked to backspace past a wrapped line.
1238  *   - A new font can be chosen using the sequence '^F<digit>' where
1239  *     <digit> is 0-7.  The directive will be ignored if
1240  *     there is no font in the specified slot.
1241  * Returns 0 if something went wrong.
1242  */
1243 {
1244     register int fontIndex;
1245     register struct txtWin *textInfo;
1246     register struct txtLine *thisLine;
1247 
1248     if ((textInfo = (struct txtWin *) XLookUpAssoc(display, textWindows, (XID) w)) == 0)
1249       return 0;
1250 
1251     /* See if screen needs to be updated */
1252     if (textInfo->flagWord & SCREENWRONG) {
1253 	TxtRepaint(display, textInfo->mainWindow);
1254     }
1255 
1256     /* See if we have to scroll down to the bottom */
1257     if (textInfo->flagWord & NOTATBOTTOM) {
1258 	WarpToBottom(display, textInfo);
1259 	textInfo->flagWord &= (~NOTATBOTTOM);
1260     }
1261 
1262     /* Undraw the current cursor */
1263     thisLine = textInfo->txtBuffer[textInfo->curLine];
1264 
1265     XFillRectangle(display, w, textInfo->bgGC,
1266 	    thisLine->lineWidth + CUROFFSET,
1267 	    textInfo->curY,
1268 	    CURSORWIDTH,
1269 	    thisLine->lineHeight);
1270 
1271     for ( /* str is ok */ ; (*str != 0) ; str++) {
1272 	/* Check to see if we are waiting on a font */
1273 	if (textInfo->flagWord & FONTNUMWAIT) {
1274 	    textInfo->flagWord &= (~FONTNUMWAIT);
1275 	    fontIndex = *str - '0';
1276 	    if ((fontIndex >= 0) && (fontIndex < MAXFONTS)) {
1277 		/* Handle font -- go get next character */
1278 		if (HandleNewFont(display, fontIndex, textInfo, DODISP))
1279 		    continue;
1280 	    }
1281 	}
1282 
1283 	/* Inline code for handling normal character case */
1284 	if ((*str >= LOWCHAR) && (*str <= HIGHCHAR)) {
1285 	    register XFontStruct *thisFont;
1286 	    register struct txtLine *thisLine;
1287 	    register int charWidth;
1288 	    int thisColor;
1289 
1290 	    /* Determine size of character */
1291 	    thisFont = &(textInfo->theFonts[textInfo->curFont]);
1292 	    thisColor = textInfo->theColors[textInfo->curFont];
1293 	    if (*str <= thisFont->min_char_or_byte2 ||
1294 		*str >= thisFont->max_char_or_byte2 ||
1295 		thisFont->per_char == 0)
1296 		charWidth = thisFont->max_bounds.width + 1;
1297 	    else
1298 		charWidth = thisFont->per_char[*str].width + 1;
1299 
1300 	    /* Check to see if line wrap is required */
1301 	    thisLine = textInfo->txtBuffer[textInfo->curLine];
1302 	    if (thisLine->lineWidth + charWidth >
1303 		(textInfo->w-BARSIZE-WRAPINDSIZE))
1304 	      {
1305 		  DrawLineWrap(display, textInfo->mainWindow,
1306 			       textInfo->w-BARSIZE-WRAPINDSIZE,
1307 			       textInfo->curY, thisLine->lineHeight,
1308 			       textInfo->fgPix);
1309 		  thisLine->lineFlags |= WRAPFLAG;
1310 		  /* Handle the spacing problem the same way as a newline */
1311 		  HandleNewLine(display, textInfo, DODISP | NONEWLINE);
1312 		  thisLine = textInfo->txtBuffer[textInfo->curLine];
1313 	      }
1314 
1315 	    /* Ready to draw character */
1316 	    XDrawString(display, textInfo->mainWindow,
1317 			DEFAULT_GC,
1318 			textInfo->curX += charWidth,
1319 			textInfo->curY + thisLine->lineHeight,
1320 			str, 1);
1321 
1322 	    /* Append character onto main buffer */
1323 	    if (textInfo->bufSpot >= textInfo->bufAlloc)
1324 	      /* Make room for more characters */
1325 	      ExpandBuffer(textInfo);
1326 	    textInfo->mainBuffer[(textInfo->bufSpot)++] =
1327 	      (textInfo->curFont << FONTSHIFT) | (*str);
1328 
1329 	    /* Update the line start array */
1330 	    thisLine->lineLength += 1;
1331 	    thisLine->lineWidth += charWidth;
1332 	} else if (*str == NEWLINE) {
1333 	    HandleNewLine(display, textInfo, DODISP);
1334 	} else if (*str == NEWFONT) {
1335 	    /* Go into waiting for font number mode */
1336 	    textInfo->flagWord |= FONTNUMWAIT;
1337 	} else if (*str == BACKSPACE) {
1338 	    HandleBackspace(display, textInfo, DODISP);
1339 	} else {
1340 	    /* Ignore all others */
1341 	}
1342     }
1343     /* Draw the cursor in its new position */
1344     thisLine = textInfo->txtBuffer[textInfo->curLine];
1345 
1346     XFillRectangle(display, w, textInfo->CursorGC,
1347 	    thisLine->lineWidth + CUROFFSET,
1348 	    textInfo->curY /* + thisLine->lineHeight */,
1349 	    CURSORWIDTH, thisLine->lineHeight);
1350 
1351     return 1;
1352 }
1353 
1354 
1355 
TxtJamStr(display,w,str)1356 int TxtJamStr(display, w, str)
1357 Display *display;
1358 Window w;			/* Text window            */
1359 register char *str;		/* NULL terminated string */
1360 /*
1361  * This is the same as TxtWriteStr except the screen is NOT updated.
1362  * After a call to this routine,  TxtRepaint should be called to
1363  * update the screen.  This routine is meant to be used to load
1364  * a text buffer with information and then allow the user to
1365  * scroll through it at will.
1366  */
1367 {
1368     register int fontIndex;
1369     register struct txtWin *textInfo;
1370 
1371     if ((textInfo = (struct txtWin *) XLookUpAssoc(display, textWindows, (XID) w)
1372 	 ) == 0)
1373       return 0;
1374 
1375     for ( /* str is ok */ ; (*str != 0) ; str++) {
1376 	/* Check to see if we are waiting on a font */
1377 	if (textInfo->flagWord & FONTNUMWAIT) {
1378 	    textInfo->flagWord &= (~FONTNUMWAIT);
1379 	    fontIndex = *str - '0';
1380 	    if ((fontIndex >= 0) && (fontIndex < MAXFONTS)) {
1381 		if (HandleNewFont(display, fontIndex, textInfo, 0)) {
1382 		    /* Handled font -- go get next character */
1383 		    continue;
1384 		}
1385 	    }
1386 	}
1387 	/* Inline code for handling normal character case */
1388 	if ((*str >= LOWCHAR) && (*str <= HIGHCHAR)) {
1389 	    register XFontStruct *thisFont;
1390 	    register struct txtLine *thisLine;
1391 	    register int charWidth;
1392 
1393 	    /* Determine size of character */
1394 	    thisFont = &(textInfo->theFonts[textInfo->curFont]);
1395 
1396 	    if (*str <= thisFont->min_char_or_byte2 ||
1397 		*str >= thisFont->max_char_or_byte2 ||
1398 		thisFont->per_char == 0)
1399 		charWidth = thisFont->max_bounds.width + 1;
1400 	    else
1401 		charWidth = thisFont->per_char[*str].width + 1;
1402 
1403 	    /* Check to see if line wrap is required */
1404 	    thisLine = textInfo->txtBuffer[textInfo->curLine];
1405 	    if (thisLine->lineWidth + charWidth >
1406 		(textInfo->w-BARSIZE-WRAPINDSIZE))
1407 	      {
1408 		  thisLine->lineFlags |= WRAPFLAG;
1409 		  /* Handle the spacing problem the same way as a newline */
1410 		  HandleNewLine(display, textInfo, NONEWLINE);
1411 		  thisLine = textInfo->txtBuffer[textInfo->curLine];
1412 	      }
1413 	    /* Append character onto main buffer */
1414 	    if (textInfo->bufSpot >= textInfo->bufAlloc)
1415 	      /* Make room for more characters */
1416 	      ExpandBuffer(textInfo);
1417 	    textInfo->mainBuffer[(textInfo->bufSpot)++] =
1418 	      (textInfo->curFont << FONTSHIFT) | (*str);
1419 
1420 	    /* Update the line start array */
1421 	    thisLine->lineLength += 1;
1422 	    thisLine->lineWidth += charWidth;
1423 	} else if (*str == NEWLINE) {
1424 	    HandleNewLine(display, textInfo, 0);
1425 	} else if (*str == NEWFONT) {
1426 	    /* Go into waiting for font number mode */
1427 	    textInfo->flagWord |= FONTNUMWAIT;
1428 	} else if (*str == BACKSPACE) {
1429 	    HandleBackspace(display, textInfo, 0);
1430 	} else {
1431 	    /* Ignore all others */
1432 	}
1433     }
1434     textInfo->flagWord |= SCREENWRONG;
1435     return 1;
1436 }
1437 
1438 
1439 
TxtRepaint(display,w)1440 int TxtRepaint(display,w)
1441 Display *display;
1442 Window w;
1443 /*
1444  * Repaints the given scrollable text window.  The routine repaints
1445  * the entire window.  For handling exposure events,  the TxtFilter
1446  * routine should be used.
1447  */
1448 {
1449     struct txtWin *textInfo;
1450     int index, ypos;
1451 
1452     if ((textInfo = (struct txtWin *) XLookUpAssoc(display, textWindows, (XID) w)
1453 	 ) == 0)
1454       return 0;
1455 
1456     /* Check to see if the screen is up to date */
1457     if (textInfo->flagWord & SCREENWRONG) {
1458 	textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
1459 	textInfo->flagWord &= (~SCREENWRONG);
1460     }
1461 
1462     ypos = YPADDING;
1463     index = textInfo->startLine;
1464     for (;;) {
1465 	DrawLine(display, textInfo, index, ypos);
1466 	if (index >= textInfo->endLine) break;
1467 	ypos += (textInfo->txtBuffer[index]->lineHeight + INTERLINE);
1468 	index++;
1469     }
1470     /* Draw the cursor (if on screen) */
1471     if (textInfo->endLine == textInfo->curLine) {
1472 	XFillRectangle(display, w, textInfo->CursorGC,
1473 		       textInfo->txtBuffer[index]->lineWidth + CUROFFSET,
1474 		       ypos /* + textInfo->txtBuffer[index]->lineHeight */,
1475 		       CURSORWIDTH, textInfo->txtBuffer[index]->lineHeight);
1476 
1477     }
1478     /* Update the scroll bar */
1479     UpdateScroll(display, textInfo);
1480     return 1;
1481 }
1482 
1483 
1484 
InsertIndex(textInfo,thisIndex,ypos)1485 static int InsertIndex(textInfo, thisIndex, ypos)
1486 struct txtWin *textInfo;	/* Text Window Information    */
1487 int thisIndex;			/* Line index of exposed line */
1488 int ypos;			/* Drawing position of line   */
1489 /*
1490  * This routine inserts the supplied line index into the copy
1491  * exposure array for 'textInfo'.  The array is kept sorted
1492  * from lowest to highest using insertion sort.  The array
1493  * is dynamically expanded if needed.
1494  */
1495 {
1496     struct expEvent *newItem;
1497     int newSize, index, downIndex;
1498 
1499     /* Check to see if we need to expand it */
1500     if ((textInfo->exposeSize + 3) >= textInfo->exposeAlloc) {
1501 	newSize = textInfo->exposeAlloc +
1502 	  (textInfo->exposeAlloc * EXPANDPERCENT / 100);
1503 	textInfo->exposeAry = (struct expEvent **)
1504 	  realloc((char *) textInfo->exposeAry,
1505 		  (unsigned) (newSize * sizeof(struct expEvent *)));
1506 	for (index = textInfo->exposeAlloc;  index < newSize;  index++)
1507 	  textInfo->exposeAry[index] = alloc(struct expEvent);
1508 	textInfo->exposeAlloc = newSize;
1509     }
1510     /* Find spot for insertion.  NOTE: last spot has big number */
1511     for (index = 0;  index <= textInfo->exposeSize;  index++) {
1512 	if (textInfo->exposeAry[index]->lineIndex >= thisIndex) {
1513 	    if (textInfo->exposeAry[index]->lineIndex > thisIndex) {
1514 		/* Insert before this entry */
1515 		newItem = textInfo->exposeAry[textInfo->exposeSize+1];
1516 		for (downIndex = textInfo->exposeSize;
1517 		     downIndex >= index;
1518 		     downIndex--)
1519 		  {
1520 		      textInfo->exposeAry[downIndex+1] =
1521 			textInfo->exposeAry[downIndex];
1522 		  }
1523 		/* Put a free structure at this spot */
1524 		textInfo->exposeAry[index] = newItem;
1525 		/* Fill it in */
1526 		textInfo->exposeAry[index]->lineIndex = thisIndex;
1527 		textInfo->exposeAry[index]->ypos = ypos;
1528 		/* Break out of loop */
1529 		textInfo->exposeSize += 1;
1530 	    }
1531 	    break;
1532 	}
1533     }
1534     return 1;
1535 }
1536 
1537 
1538 
ScrollUp(display,textInfo)1539 static int ScrollUp(display, textInfo)
1540 Display *display;
1541 struct txtWin *textInfo;	/* Text window information   */
1542 /*
1543  * This routine scrolls the indicated text window up by one
1544  * line.  The line above the current line must exist.  The
1545  * window is scrolled so that the line above the start line
1546  * is displayed at the top of the screen.  This may cause
1547  * many lines to scroll off the bottom.  The scrolling is
1548  * done using XCopyArea.  The exposure events should be caught
1549  * by ExposeCopy.
1550  */
1551 {
1552     int targetSpace;
1553 
1554     /* Make sure all exposures have been handled by now */
1555     if (textInfo->startLine == 0) return 0;
1556     targetSpace = textInfo->txtBuffer[textInfo->startLine-1]->lineHeight +
1557       INTERLINE;
1558     /* Move the area downward by the target amount */
1559     XCopyArea(display, textInfo->mainWindow, textInfo->mainWindow,
1560 	      DEFAULT_GC,
1561 	      0, YPADDING, textInfo->w - BARSIZE,
1562 	      textInfo->h, 0, targetSpace);
1563 
1564     textInfo->flagWord |= COPYEXPOSE;
1565     /* Update the text window parameters */
1566     textInfo->startLine -= 1;
1567     textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
1568 
1569     /* Clear out bottom space region */
1570     XClearArea(display, textInfo->mainWindow,
1571 	       0, textInfo->h - textInfo->bottomSpace,
1572 	       textInfo->w, textInfo->bottomSpace);
1573 
1574     UpdateExposures(display, textInfo);
1575     UpdateScroll(display, textInfo);
1576 
1577     return 1;
1578 }
1579 
1580 
ScrollToSpot(display,textInfo,ySpot)1581 static int ScrollToSpot(display, textInfo, ySpot)
1582 Display *display;
1583 struct txtWin *textInfo;	/* Text window information          */
1584 int ySpot;			/* Button position in scroll window */
1585 /*
1586  * This routine scrolls the specified text window relative to the
1587  * position of the mouse in the scroll bar.  The center of the screen
1588  * will be positioned to correspond to the mouse position.
1589  */
1590 {
1591     int targetLine, aboveLines;
1592 
1593     targetLine = textInfo->numLines * ySpot / textInfo->h;
1594     textInfo->startLine = targetLine;
1595     textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
1596     aboveLines = 0;
1597     /* Make the target line the *center* of the window */
1598     while ((textInfo->startLine > 0) &&
1599 	   (aboveLines < textInfo->endLine - targetLine))
1600       {
1601 	  textInfo->startLine -= 1;
1602 	  textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
1603 	  aboveLines++;
1604       }
1605     if (textInfo->endLine == textInfo->numLines-1) {
1606 	WarpToBottom(display, textInfo);
1607     } else {
1608 	XClearWindow(display, textInfo->mainWindow);
1609 	TxtRepaint(display, textInfo->mainWindow);
1610     }
1611     return 1;
1612 }
1613 
1614 
1615 
LineToTop(display,textInfo,pos)1616 static int LineToTop(display, textInfo, pos)
1617 Display *display;
1618 struct txtWin *textInfo;	/* Text window information */
1619 int pos;			/* Y position of mouse     */
1620 /*
1621  * This routine scrolls the screen down until the line at the
1622  * mouse position is at the top of the screen.  It stops
1623  * if it can't scroll the buffer down that far.  If the
1624  * global 'ScrollOption' is NORMSCROLL,  a smooth scroll
1625  * is used.  Otherwise,  it jumps to the right position
1626  * and repaints the screen.
1627  */
1628 {
1629     int index, sum;
1630 
1631     /* First,  we find the current line */
1632     sum = 0;
1633     for (index = textInfo->startLine;  index <= textInfo->endLine;  index++) {
1634 	if (sum + textInfo->txtBuffer[index]->lineHeight + INTERLINE> pos) break;
1635 	sum += textInfo->txtBuffer[index]->lineHeight + INTERLINE;
1636     }
1637     /* We always want to scroll down at least one line */
1638     if (index == textInfo->startLine) index++;
1639     if (ScrollOption == NORMSCROLL) {
1640 	/* Scroll down until 'index' is the starting line */
1641 	while ((textInfo->startLine < index) && ScrollDown(display, textInfo))
1642 	{
1643 	    /* Empty Loop Body */
1644 	}
1645     } else {
1646 	/* Immediately jump to correct spot */
1647 	textInfo->startLine = index;
1648 	textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
1649 	if (textInfo->endLine == textInfo->numLines-1) {
1650 	    WarpToBottom(display, textInfo);
1651 	} else {
1652 	    XClearWindow(display, textInfo->mainWindow);
1653 	    TxtRepaint(display, textInfo->mainWindow);
1654 	}
1655     }
1656     /* Check to see if at end of buffer */
1657     if (textInfo->endLine >= textInfo->numLines-1) {
1658 	textInfo->flagWord &= (~NOTATBOTTOM);
1659     }
1660     return 1;
1661 }
1662 
1663 
1664 
TopToHere(display,textInfo,pos)1665 static int TopToHere(display, textInfo, pos)
1666 Display *display;
1667 struct txtWin *textInfo;	/* Text window information */
1668 int pos;			/* Y position of mouse     */
1669 /*
1670  * This routine scrolls the screen up until the top line of
1671  * the screen is at the current Y position of the mouse.  Again,
1672  * it will stop if it can't scroll that far.  If the global
1673  * 'ScrollOption' is NORMSCROLL,  a smooth scroll is used.
1674  * If it's not,  it will simply redraw the screen at the
1675  * correct spot.
1676  */
1677 {
1678     int sum, target, linesup, index;
1679 
1680     target = pos - textInfo->txtBuffer[textInfo->startLine]->lineHeight;
1681     /* We always want to scroll up at least one line */
1682     if (target <= 0) target = 1;
1683     sum = 0;
1684     linesup = 0;
1685     /* Check to see if we are at the top anyway */
1686     if (textInfo->startLine == 0) return 0;
1687     if (ScrollOption == NORMSCROLL) {
1688 	/* Scroll up until sum of new top lines greater than target */
1689 	while ((sum < target) && ScrollUp(display, textInfo)) {
1690 	    sum += textInfo->txtBuffer[textInfo->startLine]->lineHeight;
1691 	    linesup++;
1692 	}
1693     } else {
1694 	/* Search backward to find index */
1695 	index = textInfo->startLine - 1;
1696 	while ((index > 0) && (sum < target)) {
1697 	    sum += textInfo->txtBuffer[index]->lineHeight;
1698 	    linesup++;
1699 	    index--;
1700 	}
1701 	/* Go directly to the index */
1702 	textInfo->startLine = index;
1703 	textInfo->endLine = FindEndLine(textInfo, &(textInfo->bottomSpace));
1704 	XClearWindow(display, textInfo->mainWindow);
1705 	TxtRepaint(display, textInfo->mainWindow);
1706     }
1707     /* If we scrolled,  assert we are not at bottom of buffer */
1708     if (linesup > 0) {
1709 	textInfo->flagWord |= NOTATBOTTOM;
1710     }
1711     return 1;
1712 }
1713 
1714 
1715 
TxtFilter(display,evt)1716 int TxtFilter(display, evt)
1717 Display *display;
1718 XEvent *evt;
1719 /*
1720  * This routine handles events associated with scrollable text windows.
1721  * It will handle all exposure events and any button released events
1722  * in the scroll bar of a text window.  It does NOT handle any other
1723  * events.  If it cannot handle the event,  it will return 0.
1724  */
1725 {
1726     XExposeEvent *expose = &evt->xexpose;
1727     XButtonEvent *btEvt = &evt->xbutton;
1728     XGraphicsExposeEvent *gexpose = &evt->xgraphicsexpose;
1729     XNoExposeEvent *noexpose = &evt->xnoexpose;
1730     struct txtWin *textInfo;
1731     int index, ypos;
1732     Window w, sw;
1733 
1734     if (textWindows == (XAssocTable *) 0) {
1735 	textWindows = XCreateAssocTable(32);
1736 	if (textWindows == (XAssocTable *) 0) return(0);
1737     }
1738     if (evt->type == Expose) {
1739 	w = expose->window;
1740 	sw = 0;
1741     }
1742     else if (evt->type == GraphicsExpose) {
1743 	w = gexpose->drawable;
1744 	sw = 0;
1745     }
1746     else if (evt->type == NoExpose) {
1747 	w = noexpose->drawable;
1748 	sw = 0;
1749     }
1750     else if (evt->type == ButtonRelease) {
1751 	w = btEvt->window;
1752 	sw = btEvt->subwindow;
1753     }
1754     else
1755 	return 0;
1756 
1757     if ((textInfo = (struct txtWin *)
1758 	 XLookUpAssoc(display, textWindows, (XID) w)) == 0)
1759 	return 0;
1760 
1761     /* Determine whether it's main window or not */
1762     if ((w == textInfo->mainWindow) && (sw == 0)) {
1763 	/* Main Window - handle exposures */
1764 	switch (evt->type) {
1765 	case Expose:
1766 	    ypos = 0 /*YPADDING*/;
1767 	    for (index = textInfo->startLine;
1768 		 index <= textInfo->endLine;
1769 		 index++)
1770 	      {
1771 		  int lh = textInfo->txtBuffer[index]->lineHeight;
1772 
1773 		  if (((ypos + lh) >= expose->y) &&
1774 		      (ypos <= (expose->y + expose->height)))
1775 		    {
1776 			/* Intersection region */
1777 			/* Draw line immediately */
1778 			DrawLine(display, textInfo, index, ypos);
1779 			/* And possibly draw cursor */
1780 			if (textInfo->curLine == index) {
1781 			    XFillRectangle(display, w, textInfo->CursorGC,
1782 				       textInfo->txtBuffer[index]->lineWidth +
1783 					   CUROFFSET,
1784 					   ypos,
1785 					   CURSORWIDTH,
1786 					   lh);
1787 			}
1788 		    }
1789 		  ypos += lh + INTERLINE;
1790 	      }
1791 	    break;
1792 	case GraphicsExpose:
1793 	    ypos = 0 /*YPADDING*/;
1794 	    for (index = textInfo->startLine;
1795 		 index <= textInfo->endLine;
1796 		 index++)
1797 	      {
1798 		  int lh = textInfo->txtBuffer[index]->lineHeight;
1799 
1800 		  if (((ypos + lh) >= gexpose->y) &&
1801 		      (ypos <= (gexpose->y + gexpose->height)))
1802 		    {
1803 			/* Intersection region */
1804 			/* Draw line immediately */
1805 			DrawLine(display, textInfo, index, ypos);
1806 			/* And possibly draw cursor */
1807 			if (textInfo->curLine == index) {
1808 			    XFillRectangle(display, w, textInfo->CursorGC,
1809 				    textInfo->txtBuffer[index]->lineWidth +
1810 				    CUROFFSET,
1811 				    ypos,
1812 				    CURSORWIDTH,
1813 				    lh);
1814 			}
1815 		    }
1816 		  ypos += lh + INTERLINE;
1817 	      }
1818 	    break;
1819 	case NoExpose:
1820 	    break;
1821 	default:
1822 	    /* Not one of our events */
1823 	    return 0;
1824 	}
1825     } else {
1826 	switch (evt->type) {
1827 	case Expose:
1828 	    UpdateScroll(display, textInfo);
1829 	    break;
1830 	case ButtonRelease:
1831 	    /* Find out which button */
1832 	    switch (btEvt->button) {
1833 	    case Button1:
1834 		/* Scroll up until top line is at mouse position */
1835 		TopToHere(display, textInfo, btEvt->y);
1836 		break;
1837 	    case Button2:
1838 		/* Scroll to spot relative to position */
1839 		ScrollToSpot(display, textInfo, btEvt->y);
1840 		if (textInfo->endLine >= textInfo->numLines-1) {
1841 		    textInfo->flagWord &= (~NOTATBOTTOM);
1842 		} else {
1843 		    textInfo->flagWord |= NOTATBOTTOM;
1844 		}
1845 		break;
1846 	    case Button3:
1847 		/* Scroll down until pointed line is at top */
1848 		LineToTop(display, textInfo, btEvt->y);
1849 		break;
1850 	    }
1851 	    break;
1852 	default:
1853 	    /* Not one of our events */
1854 	    return 0;
1855 	}
1856     }
1857     return 1;
1858 }
1859