📄 scrolltext.c
字号:
/* * A Scrollable Text Output Window * * David Harrison * University of California, Berkeley * 1986 * * The following is an implementation for a scrollable text output * system. It handles exposure events only (other interactions are * under user control). For scrolling, a always present scroll bar * is implemented. It detects size changes and compensates accordingly. */#include <X11/X.h>#include <X11/Xlib.h>#include <X11/X10.h>#include <sys/types.h>#include "scrollText.h"extern char *malloc();extern char *realloc();#define alloc(type) (type *) malloc(sizeof(type))#define numalloc(type, num) (type *) malloc((unsigned) (num * sizeof(type)))#define MAXINT 2147483647extern XAssocTable *XCreateAssocTable();extern caddr_t XLookUpAssoc();static XAssocTable *textWindows = (XAssocTable *) 0;#define NOOPTION -1 /* Option hasn't been set yet */#define NORMSCROLL 0 /* Smooth scroll on LineToTop and TopToHere */#define JUMPSCROLL 1 /* Jump scrolling on LineToTop and TopToHere */static int ScrollOption = NOOPTION;typedef char *Generic;#define DEFAULT_GC textInfo->fontGC[textInfo->curFont]#define BARSIZE 15#define BARBORDER 1#define MAXFONTS 8#define INITBUFSIZE 1024#define INITLINES 50#define INITEXPARY 50#define XPADDING 2#define YPADDING 2#define INTERLINE 5#define INTERSPACE 1#define CURSORWIDTH 2#define EXPANDPERCENT 40#define BUFSIZE 1024#define CUROFFSET 1#define MAXFOREIGN 250#define NOINDEX -1/* The wrap line indicator */#define WRAPINDSIZE 7#define STEMOFFSET 5#define arrow_width 7#define arrow_height 5static char arrow_bits[] = { 0x24, 0x26, 0x3f, 0x06, 0x04};#define NEWLINE '\n'#define BACKSPACE '\010'#define NEWFONT '\006'#define LOWCHAR '\040'#define HIGHCHAR '\176'#define CHARMASK 0x00ff /* Character mask */#define FONTMASK 0x0700 /* Character font */#define FONTSHIFT 8 /* Shift amount */#define WRAPFLAG 0x01 /* Line wrap flag *//* * Lines are represented by a pointer into the overall array of * 16-bit characters. The lower eight bits is used to indicate the character * (in ASCII), and the next two bits are used to indicate the font * the character should be drawn in. */typedef struct txtLine { int lineLength; /* Current line length */ int lineHeight; /* Full height of line in pixels */ int lineBaseLine; /* Current baseline of the line */ int lineWidth; /* Drawing position at end of line */ int lineText; /* Offset into master buffer */ int lineFlags; /* Line wrap flag is here */};/* * For ExposeCopy events, we queue up the redraw requests collapsing * them into line redraw requests until the CopyExpose event arrives. * The queue is represented as a dynamic array of the following * structure: */typedef struct expEvent { int lineIndex; /* Index of line to redraw */ int ypos; /* Drawing position of line */};/* * The text buffer is represented using a dynamic counted array * of 16-bit quantities. This array expands as needed. * For the screen representation, a dynamic counted array * of line structures is used. This array points into the * text buffer to denote the start of each line and its parameters. * The windows are configured as one overall window which contains * the scroll bar as a sub-window along its right edge. Thus, * the text drawing space is actually w-BARSIZE. */#define NOTATBOTTOM 0x01 /* Need to scroll to bottom before appending */#define FONTNUMWAIT 0x02 /* Waiting for font number */#define COPYEXPOSE 0x04 /* Need to process a copy expose event */#define SCREENWRONG 0x08 /* TxtJamStr has invalidated screen contents */typedef struct txtWin { /* Basic text buffer */ int bufAlloc; /* Allocated size of buffer */ int bufSpot; /* Current writing position in buffer */ short *mainBuffer; /* Main buffer of text */ /* Line information */ int numLines; /* Number of display lines in buffer */ int allocLines; /* Number of lines allocated */ struct txtLine **txtBuffer; /* Dynamic array of lines */ /* Current Window display information */ Window mainWindow; /* Text display window */ Window scrollBar; /* Subwindow for scroll bar */ Pixmap arrowMap; /* line wrap indicator */ int bgPix, fgPix; /* Background and cursor */ GC CursorGC; /* gc for the cursor */ GC bgGC; /* gc for erasing things */ GC fontGC[MAXFONTS]; /* gc for doing fonts */ XFontStruct theFonts[MAXFONTS];/* Display fonts */ int theColors[MAXFONTS]; /* foregrounds of the fonts */ int curFont; /* current font for tracking */ int w, h; /* Current size */ int startLine; /* Top line in display */ int endLine; /* Bottom line in display */ int bottomSpace; /* Space at bottom of screen */ int flagWord; /* If non-zero, not at end */ /* For handling ExposeCopy events */ int exposeSize; /* Current size of array */ int exposeAlloc; /* Allocated size */ struct expEvent **exposeAry;/* Array of line indices */ /* Drawing position information */ int curLine; /* Current line in buffer */ int curX; /* Current horizontal positi */ int curY; /* Current vertical drawing */};/* Flags for the various basic character handling functions */#define DODISP 0x01 /* Update the display */#define NONEWLINE 0x02 /* Dont append newline */static int InitLine(newLine)struct txtLine *newLine; /* Newly created line structure *//* * This routine initializes a newly created line structure. */{ newLine->lineLength = 0; newLine->lineHeight = 0; newLine->lineBaseLine = 0; newLine->lineWidth = XPADDING; newLine->lineText = NOINDEX; newLine->lineFlags = 0; return 1;}int TxtGrab(display, txtWin, program, mainFont, bg, fg, cur)Display *display; /* display window is on */Window txtWin; /* Window to take over as scrollable text */char *program; /* Program name for Xdefaults */XFontStruct *mainFont; /* Primary text font */int bg, fg, cur; /* Background, foreground, and cursor colors *//* * This routine takes control of 'txtWin' and makes it into a scrollable * text output window. It will create a sub-window for the scroll bar * with a background of 'bg' and an bar with color 'fg'. Both fixed width * and variable width fonts are supported. Additional fonts can be loaded * using 'TxtAddFont'. Returns 0 if there were problems, non-zero if * everything went ok. */{ struct txtWin *newWin; /* Text package specific information */ XWindowAttributes winInfo; /* Window information */ int index; XGCValues gc_val; if (textWindows == (XAssocTable *) 0) { textWindows = XCreateAssocTable(32); if (textWindows == (XAssocTable *) 0) return(0); } if (XGetWindowAttributes(display, txtWin, &winInfo) == 0) return 0; if (ScrollOption == NOOPTION) { /* Read to see if the user wants jump scrolling or not */ if (XGetDefault(display, program, "JumpScroll")) { ScrollOption = JUMPSCROLL; } else { ScrollOption = NORMSCROLL; } } /* Initialize local structure */ newWin = alloc(struct txtWin); /* Initialize arrow pixmap */ newWin->arrowMap = XCreatePixmapFromBitmapData(display, txtWin, arrow_bits, arrow_width, arrow_height, cur, bg, DisplayPlanes(display, 0)); newWin->bufAlloc = INITBUFSIZE; newWin->bufSpot = 0; newWin->mainBuffer = numalloc(short, INITBUFSIZE); newWin->numLines = 1; newWin->allocLines = INITLINES; newWin->txtBuffer = numalloc(struct txtLine *, INITLINES); for (index = 0; index < INITLINES; index++) { newWin->txtBuffer[index] = alloc(struct txtLine); InitLine(newWin->txtBuffer[index]); } /* Window display information */ newWin->mainWindow = txtWin; newWin->w = winInfo.width; newWin->h = winInfo.height; newWin->startLine = 0; newWin->endLine = 0; newWin->bottomSpace = winInfo.height - YPADDING - mainFont->ascent - mainFont->descent - INTERLINE; newWin->flagWord = 0; newWin->bgPix = bg; newWin->fgPix = fg; /* Scroll Bar Creation */ newWin->scrollBar = XCreateSimpleWindow(display, txtWin, winInfo.width - BARSIZE, 0, BARSIZE - (2*BARBORDER), winInfo.height - (2*BARBORDER), BARBORDER, fg, bg); XSelectInput(display, newWin->scrollBar, ExposureMask|ButtonReleaseMask); XMapRaised(display, newWin->scrollBar); /* Font and Color Initialization */ newWin->theFonts[0] = *mainFont; newWin->theColors[0] = fg; gc_val.function = GXcopy; gc_val.plane_mask = AllPlanes; gc_val.foreground = fg; gc_val.background = bg; gc_val.graphics_exposures = 1; gc_val.font = mainFont->fid; gc_val.line_width = 1; gc_val.line_style = LineSolid; newWin->fontGC[0] = XCreateGC(display, txtWin, GCFunction | GCPlaneMask | GCForeground | GCBackground | GCGraphicsExposures | GCFont, &gc_val); gc_val.foreground = cur; newWin->CursorGC = XCreateGC(display, txtWin, GCFunction | GCPlaneMask | GCForeground | GCBackground | GCLineStyle | GCLineWidth, &gc_val); gc_val.foreground = bg; newWin->bgGC = XCreateGC(display, txtWin, GCFunction | GCPlaneMask | GCForeground | GCBackground | GCGraphicsExposures | GCFont, &gc_val); for (index = 1; index < MAXFONTS; index++) { newWin->theFonts[index].fid = 0; newWin->fontGC[index] = 0; } /* Initialize size of first line */ newWin->txtBuffer[0]->lineHeight = newWin->theFonts[0].ascent + newWin->theFonts[0].descent; newWin->txtBuffer[0]->lineText = 0; /* ExposeCopy array initialization */ newWin->exposeSize = 0; newWin->exposeAlloc = INITEXPARY; newWin->exposeAry = numalloc(struct expEvent *, INITEXPARY); for (index = 0; index < newWin->exposeAlloc; index++) newWin->exposeAry[index] = alloc(struct expEvent); /* Put plus infinity in last slot for sorting purposes */ newWin->exposeAry[0]->lineIndex = MAXINT; /* Drawing Position Information */ newWin->curLine = 0; newWin->curX = 0; newWin->curY = YPADDING + mainFont->ascent + mainFont->descent; /* Attach it to both windows */ XMakeAssoc(display, textWindows, (XID) txtWin, (caddr_t) newWin); XMakeAssoc(display, textWindows, (XID) newWin->scrollBar, (caddr_t) newWin); return 1;}int TxtRelease(display, w)Display *display;Window w; /* Window to release *//* * This routine releases all resources associated with the * specified window which are consumed by the text * window package. This includes the entire text buffer, line start * array, and the scroll bar window. However, the window * itself is NOT destroyed. The routine will return zero if * the window is not owned by the text window package. */{ struct txtWin *textInfo; int index; if ((textInfo = (struct txtWin *) XLookUpAssoc(display, textWindows, (XID) w)) == 0) return 0; for (index = 0; index < MAXFONTS; index++) if (textInfo->fontGC[index] != 0) XFreeGC(display, textInfo->fontGC[index]); free((Generic) textInfo->mainBuffer); for (index = 0; index < textInfo->numLines; index++) { free((Generic) textInfo->txtBuffer[index]); } free((Generic) textInfo->txtBuffer); XDestroyWindow(display, textInfo->scrollBar); for (index = 0; index < textInfo->exposeSize; index++) { free((Generic) textInfo->exposeAry[index]); } free((Generic) textInfo->exposeAry); XDeleteAssoc(display, textWindows, (XID) w); free((Generic) textInfo); return 1;}static int RecompBuffer(textInfo)struct txtWin *textInfo; /* Text window information *//* * This routine recomputes all line breaks in a buffer after * a change in window size or font. This is done by throwing * away the old line start array and recomputing it. Although * a lot of this work is also done elsewhere, it has been included * inline here for efficiency. */{ int startPos, endSize, linenum; register int index, chsize, curfont; register short *bufptr; register XFontStruct *fontptr; register struct txtLine *lineptr; char theChar; /* Record the old position so we can come back to it */ for (startPos = textInfo->txtBuffer[textInfo->startLine]->lineText; (startPos > 0) && (textInfo->mainBuffer[startPos] != '\n'); startPos--) /* null loop body */; /* Clear out the old line start array */ for (index = 0; index < textInfo->numLines; index++) { InitLine(textInfo->txtBuffer[index]); } /* Initialize first line */ textInfo->txtBuffer[0]->lineHeight = textInfo->theFonts[0].ascent + textInfo->theFonts[0].descent; textInfo->txtBuffer[0]->lineText = 0; /* Process the text back into lines */ endSize = textInfo->w - BARSIZE - WRAPINDSIZE; bufptr = textInfo->mainBuffer; lineptr = textInfo->txtBuffer[0]; linenum = 0; fontptr = &(textInfo->theFonts[0]); curfont = 0; for (index = 0; index < textInfo->bufSpot; index++) { theChar = bufptr[index] & CHARMASK; if ((bufptr[index] & FONTMASK) != curfont) { int newFontNum, heightDiff; /* Switch fonts */ newFontNum = (bufptr[index] & FONTMASK) >> FONTSHIFT; if (textInfo->theFonts[newFontNum].fid != 0) { /* Valid font */ curfont = bufptr[index] & FONTMASK; fontptr = &(textInfo->theFonts[newFontNum]); heightDiff = (fontptr->ascent + fontptr->descent) - lineptr->lineHeight; if (heightDiff < 0) heightDiff = 0; lineptr->lineHeight += heightDiff; } } if (theChar == '\n') { /* Handle new line */ if (linenum >= textInfo->allocLines-1) /* Expand number of lines */ ExpandLines(textInfo); linenum++; lineptr = textInfo->txtBuffer[linenum]; /* Initialize next line */ lineptr->lineHeight = fontptr->ascent + fontptr->descent; lineptr->lineText = index+1; /* Check to see if its the starting line */ if (index == startPos) textInfo->startLine = linenum; } else { /* Handle normal character */ chsize = CharSize(textInfo, linenum, index); if (lineptr->lineWidth + chsize > endSize) { /* Handle line wrap */ lineptr->lineFlags |= WRAPFLAG; if (linenum >= textInfo->allocLines-1) /* Expand number of lines */ ExpandLines(textInfo); linenum++; lineptr = textInfo->txtBuffer[linenum]; /* Initialize next line */ lineptr->lineHeight = fontptr->ascent + fontptr->descent; lineptr->lineText = index; lineptr->lineLength = 1; lineptr->lineWidth += chsize; } else { /* Handle normal addition of character */ lineptr->lineLength += 1; lineptr->lineWidth += chsize; } } } /* We now have a valid line array. Let's clean up some other fields. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -