|
|
1.1 root 1: #ifndef lint
2: static char rcsid[] = "$Header: Text.c,v 1.4 87/09/13 23:32:44 newman 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: /* File: Text.c */
28:
29: #include "Intrinsic.h"
30: #include "Text.h"
31: #include "TextP.h"
32: #include "Scroll.h"
33: #include "Atoms.h"
34: #include <sys/file.h>
35: #include <X11/Xutil.h>
36: #include <strings.h>
37:
38: extern void bcopy();
39:
40: #define BufMax 1000
41: #define abs(x) (((x) < 0) ? (-(x)) : (x))
42: #define min(x,y) ((x) < (y) ? (x) : (y))
43: #define max(x,y) ((x) > (y) ? (x) : (y))
44: #define GETLASTPOS (*(ctx->text.source->scan)) (ctx->text.source, 0, XtstFile, XtsdRight, 1, TRUE)
45: #define BUTTONMASK 0x143d
46:
47: #define yMargin 2
48: #define zeroPosition ((XtTextPosition) 0)
49:
50: extern void BuildLineTable ();
51:
52: /****************************************************************
53: *
54: * Full class record constant
55: *
56: ****************************************************************/
57:
58: extern caddr_t defaultTextTranslations;
59:
60: static XtResource resources[] = {
61: {XtNtextOptions, XtCTextOptions, XrmRInt, sizeof (int),
62: XtOffset(TextWidget, text.options), XrmRString, "0"},
63: {XtNdisplayPosition, XtCTextPosition, XrmRInt,
64: sizeof (XtTextPosition), XtOffset(TextWidget, text.lt.top),
65: XrmRString, "0"},
66: {XtNinsertPosition, XtCTextPosition, XtRInt,
67: sizeof(XtTextPosition), XtOffset(TextWidget, text.insertPos),
68: XrmRString, "0"},
69: {XtNleftMargin, XtCMargin, XrmRInt, sizeof (int),
70: XtOffset(TextWidget, text.leftmargin), XrmRString, "2"},
71: {XtNselectionArray, XtCSelectionArray, XrmRPointer,
72: sizeof(SelectionArray), XtOffset(TextWidget, text.sarray),
73: XrmRPointer, NULL},
74: {XtNtextSource, XtCTextSource, XrmRPointer, sizeof (caddr_t),
75: XtOffset(TextWidget, text.source), XrmRPointer, NULL},
76: {XtNtextSink, XtCTextSink, XrmRPointer, sizeof (caddr_t),
77: XtOffset(TextWidget, text.sink), XrmRPointer, NULL},
78: {XtNselection, XtCSelection, XrmRPointer, sizeof(caddr_t),
79: XtOffset(TextWidget, text.s), XrmRPointer, NULL},
80: {XtNeventBindings, XtCEventBindings, XtRStringTable,
81: sizeof(_XtTranslations), XtOffset(TextWidget, core.translations),
82: XtRStringTable, (caddr_t)&defaultTextTranslations},
83: };
84:
85:
86: static void Initialize(request, new)
87: Widget request, new;
88: {
89: TextWidget ctx = (TextWidget) new;
90:
91: if (ctx->core.width == 0)
92: ctx->core.width = 200;
93: if (ctx->core.height == 0)
94: ctx->core.height = 200;
95:
96: ctx->text.lt.lines = 0;
97: ctx->text.lt.info = NULL;
98: ctx->text.s.left = ctx->text.s.right = 0;
99: ctx->text.s.type = XtselectPosition;
100: ctx->text.sbar = ctx->text.outer = NULL;
101: ctx->text.sarray[0] = XtselectPosition;
102: ctx->text.sarray[1] = XtselectWord;
103: ctx->text.sarray[2] = XtselectLine;
104: ctx->text.sarray[3] = XtselectParagraph;
105: ctx->text.sarray[4] = XtselectAll;
106: ctx->text.sarray[5] = XtselectNull;
107: ctx->text.showposition = TRUE;
108: ctx->text.lastPos = GETLASTPOS;
109: ctx->text.dialog = NULL;
110: ctx->text.updateFrom = (XtTextPosition *) XtMalloc(1);
111: ctx->text.updateTo = (XtTextPosition *) XtMalloc(1);
112: ctx->text.numranges = ctx->text.maxranges = 0;
113: ctx->text.gc = DefaultGCOfScreen(XtScreen(ctx));
114: BuildLineTable(ctx, ctx->text.lt.top);
115: /* what about this ugly scrollbar stuff?
116: if (ctx->text.options & scrollVertical) {
117: scrollMgrArgs[0].value =
118: scrollBarArgs[0].value = (caddr_t)(XtWindow(ctx));
119: ctx->text.outer =
120: XtScrollMgrCreate(ctx->core.display, parent, scrollMgrArgs, XtNumber(scrollMgrArgs));
121: XtWindow(ctx) = XtScrollMgrGetChild(ctx->core.display, ctx->text.outer);
122: ctx->text.sbar =
123: XtCreateWidget("scrollbar", scrollbarWidgetClass, ctx->text.outer,
124: scrollBarArgs, XtNumber(scrollBarArgs));
125: XMapSubwindows(ctx->core.display, ctx->text.outer);
126: (void) XtSetEventHandler(ctx->core.display, ctx->text.outer, ProcessTextEvent,
127: StructureNotifyMask, (caddr_t) ctx);
128: }
129: */
130: }
131:
132: static void Realize( w, valueMask, attributes )
133: Widget w;
134: Mask valueMask;
135: XSetWindowAttributes *attributes;
136: {
137: TextWidget ctx = (TextWidget)w;
138: if (ctx->text.sbar) XtRealizeWidget(ctx->text.sbar);
139: ctx->core.window =
140: XCreateWindow(
141: XtDisplay(w), w->core.parent->core.window,
142: w->core.x, w->core.y,
143: w->core.width, w->core.height, w->core.border_width,
144: w->core.depth, InputOutput, (Visual *)CopyFromParent,
145: valueMask, attributes);
146: }
147:
148: /* Utility routines for support of Text */
149:
150:
151: /*
152: * Procedure to manage insert cursor visibility for editable text. It uses
153: * the value of ctx->insertPos and an implicit argument. In the event that
154: * position is immediately preceded by an eol graphic, then the insert cursor
155: * is displayed at the beginning of the next line.
156: */
157: static void InsertCursor (ctx, state)
158: TextWidget ctx;
159: InsertState state;
160: {
161: Position x, y;
162: int dy, line, visible;
163: XtTextBlock text;
164:
165: if (ctx->text.lt.lines < 1) return;
166: visible = LineAndXYForPosition(ctx, ctx->text.insertPos, &line, &x, &y);
167: if (line < ctx->text.lt.lines)
168: dy = (ctx->text.lt.info[line + 1].y - ctx->text.lt.info[line].y) + 1;
169: else
170: dy = (ctx->text.lt.info[line].y - ctx->text.lt.info[line - 1].y) + 1;
171:
172: /** If the insert position is just after eol then put it on next line **/
173: if (x > ctx->text.leftmargin &&
174: ctx->text.insertPos > 0 &&
175: ctx->text.insertPos >= ctx->text.lastPos) {
176: /* reading the source is bogus and this code should use scan */
177: (*(ctx->text.source->read)) (ctx->text.source, ctx->text.insertPos - 1, &text, 1);
178: if (text.ptr[0] == '\n') {
179: x = ctx->text.leftmargin;
180: y += dy;
181: }
182: }
183: y += dy;
184: if (visible)
185: (*(ctx->text.sink->insertCursor))(ctx, x, y, state);
186: }
187:
188:
189: /*
190: * Procedure to register a span of text that is no longer valid on the display
191: * It is used to avoid a number of small, and potentially overlapping, screen
192: * updates. [note: this is really a private procedure but is used in
193: * multiple modules].
194: */
195: _XtTextNeedsUpdating(ctx, left, right)
196: TextWidget ctx;
197: XtTextPosition left, right;
198: {
199: int i;
200: if (left < right) {
201: for (i = 0; i < ctx->text.numranges; i++) {
202: if (left <= ctx->text.updateTo[i] && right >= ctx->text.updateFrom[i]) {
203: ctx->text.updateFrom[i] = min(left, ctx->text.updateFrom[i]);
204: ctx->text.updateTo[i] = max(right, ctx->text.updateTo[i]);
205: return;
206: }
207: }
208: ctx->text.numranges++;
209: if (ctx->text.numranges > ctx->text.maxranges) {
210: ctx->text.maxranges = ctx->text.numranges;
211: i = ctx->text.maxranges * sizeof(XtTextPosition);
212: ctx->text.updateFrom = (XtTextPosition *)
213: XtRealloc((char *)ctx->text.updateFrom, (unsigned) i);
214: ctx->text.updateTo = (XtTextPosition *)
215: XtRealloc((char *)ctx->text.updateTo, (unsigned) i);
216: }
217: ctx->text.updateFrom[ctx->text.numranges - 1] = left;
218: ctx->text.updateTo[ctx->text.numranges - 1] = right;
219: }
220: }
221:
222:
223: /*
224: * Procedure to read a span of text in Ascii form. This is purely a hack and
225: * we probably need to add a function to sources to provide this functionality.
226: * [note: this is really a private procedure but is used in multiple modules].
227: */
228: char *_XtTextGetText(ctx, left, right)
229: TextWidget ctx;
230: XtTextPosition left, right;
231: {
232: char *result, *tempResult;
233: int length, resultLength;
234: XtTextBlock text;
235: XtTextPosition end, nend;
236:
237: resultLength = right - left + 10; /* Bogus? %%% */
238: result = (char *)XtMalloc((unsigned) resultLength);
239: end = (*(ctx->text.source->read))(ctx->text.source, left, &text, right - left);
240: (void) strncpy(result, text.ptr, text.length);
241: length = text.length;
242: while (end < right) {
243: nend = (*(ctx->text.source->read))(ctx->text.source, end, &text, right - end);
244: tempResult = result + length;
245: (void) strncpy(tempResult, text.ptr, text.length);
246: length += text.length;
247: end = nend;
248: }
249: result[length] = 0;
250: return result;
251: }
252:
253:
254:
255: /*
256: * This routine maps an x and y position in a window that is displaying text
257: * into the corresponding position in the source.
258: */
259: static XtTextPosition PositionForXY (ctx, x, y)
260: TextWidget ctx;
261: Position x,y;
262: {
263: /* it is illegal to call this routine unless there is a valid line table! */
264: int width, fromx, line;
265: XtTextPosition position, resultstart, resultend;
266:
267: /*** figure out what line it is on ***/
268: for (line = 0; line < ctx->text.lt.lines - 1; line++) {
269: if (y <= ctx->text.lt.info[line + 1].y)
270: break;
271: }
272: position = ctx->text.lt.info[line].position;
273: if (position >= ctx->text.lastPos)
274: return ctx->text.lastPos;
275: fromx = ctx->text.lt.info[line].x; /* starting x in line */
276: width = x - fromx; /* num of pix from starting of line */
277: (*(ctx->text.sink->resolve)) (ctx, position, fromx, width,
278: &resultstart, &resultend);
279: if (resultstart >= ctx->text.lt.info[line + 1].position)
280: resultstart = (*(ctx->text.source->scan))(ctx->text.source,
281: ctx->text.lt.info[line + 1].position, XtstPositions, XtsdLeft, 1, TRUE);
282: return resultstart;
283: }
284:
285: /*
286: * This routine maps a source position in to the corresponding line number
287: * of the text that is displayed in the window.
288: */
289: int LineForPosition (ctx, position)
290: TextWidget ctx;
291: XtTextPosition position;
292: /* it is illegal to call this routine unless there is a valid line table!*/
293: {
294: int line;
295:
296: if (position <= ctx->text.lt.info[0].position)
297: return 0;
298: for (line = 0; line < ctx->text.lt.lines; line++)
299: if (position < ctx->text.lt.info[line + 1].position)
300: break;
301: return line;
302: }
303:
304: /*
305: * This routine maps a source position into the corresponding line number
306: * and the x, y coordinates of the text that is displayed in the window.
307: */
308: static int LineAndXYForPosition (ctx, pos, line, x, y)
309: TextWidget ctx;
310: XtTextPosition pos;
311: int *line;
312: Position *x, *y;
313: /* it is illegal to call this routine unless there is a valid line table!*/
314: {
315: XtTextPosition linePos, endPos;
316: int visible, realW, realH;
317:
318: *line = 0;
319: *x = ctx->text.leftmargin;
320: *y = yMargin;
321: visible = IsPositionVisible(ctx, pos);
322: if (visible) {
323: *line = LineForPosition(ctx, pos);
324: *y = ctx->text.lt.info[*line].y;
325: *x = ctx->text.lt.info[*line].x;
326: linePos = ctx->text.lt.info[*line].position;
327: (*(ctx->text.sink->findDistance))(ctx, linePos,
328: *x, pos, &realW, &endPos, &realH);
329: *x = *x + realW;
330: }
331: return visible;
332: }
333:
334: /*
335: * This routine builds a line table. It does this by starting at the
336: * specified position and measuring text to determine the staring position
337: * of each line to be displayed. It also determines and saves in the
338: * linetable all the required metrics for displaying a given line (e.g.
339: * x offset, y offset, line length, etc.).
340: */
341: static void BuildLineTable (ctx, position)
342: TextWidget ctx;
343: XtTextPosition position;
344: {
345: Position x, y;
346: Dimension width, realW, realH;
347: int line, lines;
348: XtTextPosition startPos, endPos;
349: Boolean rebuild;
350:
351: rebuild = (Boolean) (position != ctx->text.lt.top);
352: lines = (*(ctx->text.sink->maxLines))(ctx, ctx->core.height);
353: if (ctx->text.lt.info != NULL && lines != ctx->text.lt.lines) {
354: XtFree((char *) ctx->text.lt.info);
355: ctx->text.lt.info = NULL;
356: }
357: if (ctx->text.lt.info == NULL) {
358: ctx->text.lt.info = (LineTableEntry *)
359: XtMalloc((unsigned)sizeof(LineTableEntry) * (lines + 1));
360: for (line = 0; line < lines; line++) {
361: ctx->text.lt.info[line].position = 0;
362: ctx->text.lt.info[line].y = 0;
363: }
364: rebuild = TRUE;
365: }
366: else
367: lines = ctx->text.lt.lines;
368: if (rebuild) {
369: ctx->text.lt.top = position;
370: ctx->text.lt.lines = lines;
371: startPos = position;
372: y = yMargin;
373: for (line = 0; line <= ctx->text.lt.lines; line++) {
374: x = ctx->text.leftmargin;
375: ctx->text.lt.info[line].x = x;
376: ctx->text.lt.info[line].y = y;
377: ctx->text.lt.info[line].position = startPos;
378: if (startPos <= ctx->text.lastPos) {
379: width = (ctx->text.options & resizeWidth) ? 9999 : ctx->core.width - x;
380: (*(ctx->text.sink->findPosition))(ctx,
381: startPos, x,
382: width, (ctx->text.options & wordBreak),
383: &endPos, &realW, &realH);
384: if (!(ctx->text.options & wordBreak) && endPos < ctx->text.lastPos) {
385: endPos = (*(ctx->text.source->scan))(ctx->text.source, startPos,
386: XtstEOL, XtsdRight, 1, TRUE);
387: if (endPos == startPos)
388: endPos = ctx->text.lastPos + 1;
389: }
390: ctx->text.lt.info[line].endX = realW + x;
391: startPos = endPos;
392: }
393: else ctx->text.lt.info[line].endX = x;
394: y = y + realH;
395: }
396: }
397: }
398:
399: /*
400: * This routine is used to re-display the entire window, independent of
401: * its current state.
402: */
403: void ForceBuildLineTable(ctx)
404: TextWidget ctx;
405: {
406: XtTextPosition position;
407:
408: position = ctx->text.lt.top;
409: ctx->text.lt.top++; /* ugly, but it works */
410: BuildLineTable(ctx, position);
411: }
412:
413: /*
414: * This routine is used by Text to notify an associated scrollbar of the
415: * correct metrics (position and shown fraction) for the text being currently
416: * displayed in the window.
417: */
418: static void SetScrollBar(ctx)
419: TextWidget ctx;
420: {
421: float first, last;
422: if (ctx->text.sbar) {
423: if ((ctx->text.lastPos > 0) && (ctx->text.lt.lines > 0)) {
424: first = ctx->text.lt.top;
425: first /= ctx->text.lastPos;
426: /* Just an approximation */
427: last = ctx->text.lt.info[ctx->text.lt.lines].position;
428: last /= ctx->text.lastPos;
429: }
430: else {
431: first = 0.0;
432: last = 1.0;
433: }
434: XtScrollBarSetThumb(ctx->text.sbar, first, last - first);
435: }
436: }
437:
438:
439: /*
440: * The routine will scroll the displayed text by lines. If the arg is
441: * positive, move up; otherwise, move down. [note: this is really a private
442: * procedure but is used in multiple modules].
443: */
444: _XtTextScroll(ctx, n)
445: TextWidget ctx;
446: int n;
447: {
448: XtTextPosition top, target;
449: if (n >= 0) {
450: top = min(ctx->text.lt.info[n].position, ctx->text.lastPos);
451: BuildLineTable(ctx, top);
452: if (top >= ctx->text.lastPos)
453: DisplayTextWindow(ctx);
454: else {
455: XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx), ctx->text.gc,
456: 0, ctx->text.lt.info[n].y,
457: 9999, (Dimension)ctx->core.height - ctx->text.lt.info[n].y,
458: 0, ctx->text.lt.info[0].y);
459: (*(ctx->text.sink->clearToBackground))(ctx, 0,
460: ctx->text.lt.info[0].y + ctx->core.height - ctx->text.lt.info[n].y,
461: 9999, 9999);
462: if (n < ctx->text.lt.lines) n++;
463: _XtTextNeedsUpdating(ctx,
464: ctx->text.lt.info[ctx->text.lt.lines - n].position, ctx->text.lastPos);
465: SetScrollBar(ctx);
466: }
467: } else {
468: Dimension tempHeight;
469: n = -n;
470: target = ctx->text.lt.top;
471: top = (*(ctx->text.source->scan))(ctx->text.source, target, XtstEOL,
472: XtsdLeft, n+1, FALSE);
473: tempHeight = ctx->text.lt.info[ctx->text.lt.lines-n].y;
474: BuildLineTable(ctx, top);
475: if (ctx->text.lt.info[n].position == target) {
476: XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx), ctx->text.gc,
477: 0, ctx->text.lt.info[0].y, 9999, tempHeight,
478: 0, ctx->text.lt.info[n].y);
479: _XtTextNeedsUpdating(ctx,
480: ctx->text.lt.info[0].position, ctx->text.lt.info[n].position);
481: SetScrollBar(ctx);
482: } else if (ctx->text.lt.top != target) DisplayTextWindow(ctx);
483: }
484: }
485:
486: /*
487: * The routine will scroll the displayed text by pixels. If the arg is
488: * positive, move up; otherwise, move down.
489: */
490: /*ARGSUSED*/ /* keep lint happy */
491: static int ScrollUpDownProc (w, data, pix)
492: Widget w;
493: int data;
494: int pix;
495: {
496: TextWidget ctx = (TextWidget)w;
497: int apix, line;
498: _XtTextPrepareToUpdate(ctx);
499: apix = abs(pix);
500: for (line = 1;
501: line < ctx->text.lt.lines && apix > ctx->text.lt.info[line + 1].y;
502: line++);
503: if (pix >= 0)
504: _XtTextScroll(ctx, line);
505: else
506: _XtTextScroll(ctx, -line);
507: _XtTextExecuteUpdate(ctx);
508: }
509:
510: /*
511: * The routine "thumbs" the displayed text. Thumbing means reposition the
512: * displayed view of the source to a new position determined by a fraction
513: * of the way from beginning to end. Ideally, this should be determined by
514: * the number of displayable lines in the source. This routine does it as a
515: * fraction of the first position and last position and then normalizes to
516: * the start of the line containing the position.
517: */
518: /*ARGSUSED*/ /* keep lint happy */
519: static int ThumbProc (w, data, where)
520: Widget w;
521: int data;
522: float where;
523: /* BUG/deficiency: The normalize to line portion of this routine will
524: * cause thumbing to always position to the start of the source.
525: */
526: {
527:
528: TextWidget ctx= (TextWidget)w;
529: XtTextPosition position;
530: _XtTextPrepareToUpdate(ctx);
531: position = where * ctx->text.lastPos;
532: position = (*(ctx->text.source->scan))(ctx->text.source, position, XtstEOL, XtsdLeft,
533: 1, FALSE);
534: BuildLineTable(ctx, position);
535: DisplayTextWindow(ctx);
536: _XtTextExecuteUpdate(ctx);
537: }
538:
539:
540: int _XtTextSetNewSelection(ctx, left, right)
541: TextWidget ctx;
542: XtTextPosition left, right;
543: {
544: XtTextPosition pos;
545:
546: if (left < ctx->text.s.left) {
547: pos = min(right, ctx->text.s.left);
548: _XtTextNeedsUpdating(ctx, left, pos);
549: }
550: if (left > ctx->text.s.left) {
551: pos = min(left, ctx->text.s.right);
552: _XtTextNeedsUpdating(ctx, ctx->text.s.left, pos);
553: }
554: if (right < ctx->text.s.right) {
555: pos = max(right, ctx->text.s.left);
556: _XtTextNeedsUpdating(ctx, pos, ctx->text.s.right);
557: }
558: if (right > ctx->text.s.right) {
559: pos = max(left, ctx->text.s.right);
560: _XtTextNeedsUpdating(ctx, pos, right);
561: }
562:
563: ctx->text.s.left = left;
564: ctx->text.s.right = right;
565: }
566:
567:
568:
569: /*
570: * This internal routine deletes the text from pos1 to pos2 in a source and
571: * then inserts, at pos1, the text that was passed. As a side effect it
572: * "invalidates" that portion of the displayed text (if any).
573: */
574: int ReplaceText (ctx, pos1, pos2, text)
575: TextWidget ctx;
576: XtTextPosition pos1, pos2;
577: XtTextBlock *text;
578:
579: /* it is illegal to call this routine unless there is a valid line table!*/
580: {
581: int i, line1, line2, visible, delta, error;
582: Position x, y;
583: Dimension realW, realH, width;
584: XtTextPosition startPos, endPos, updateFrom;
585:
586: /* the insertPos may not always be set to the right spot in XttextAppend */
587: if ((pos1 == ctx->text.insertPos) &&
588: ((*(ctx->text.source->editType))(ctx->text.source) == XttextAppend)) {
589: ctx->text.insertPos = GETLASTPOS;
590: pos2 = pos2 - pos1 + ctx->text.insertPos;
591: pos1 = ctx->text.insertPos;
592: }
593: updateFrom = (*(ctx->text.source->scan))(ctx->text.source, pos1, XtstWhiteSpace, XtsdLeft,
594: 1, TRUE);
595: updateFrom = (*(ctx->text.source->scan))(ctx->text.source, updateFrom, XtstPositions, XtsdLeft,
596: 1, TRUE);
597: startPos = max(updateFrom, ctx->text.lt.top);
598: visible = LineAndXYForPosition(ctx, startPos, &line1, &x, &y);
599: error = (*(ctx->text.source->replace))(ctx->text.source, pos1, pos2, text, &delta);
600: if (error) return error;
601: ctx->text.lastPos = GETLASTPOS;
602: if (ctx->text.lt.top >= ctx->text.lastPos) {
603: BuildLineTable(ctx, ctx->text.lastPos);
604: ClearWindow(ctx);
605: SetScrollBar(ctx);
606: return error;
607: }
608: if (delta < ctx->text.lastPos) {
609: for (i = 0; i < ctx->text.numranges; i++) {
610: if (ctx->text.updateFrom[i] > pos1)
611: ctx->text.updateFrom[i] += delta;
612: if (ctx->text.updateTo[i] >= pos1)
613: ctx->text.updateTo[i] += delta;
614: }
615: }
616:
617: line2 = LineForPosition(ctx, pos1);
618: /*
619: * fixup all current line table entries to reflect edit.
620: * BUG: it is illegal to do arithmetic on positions. This code should
621: * either use scan or the source needs to provide a function for doing
622: * position arithmetic.
623: */
624: for (i = line2 + 1; i <= ctx->text.lt.lines; i++)
625: ctx->text.lt.info[i].position += delta;
626:
627: endPos = pos1;
628: /*
629: * Now process the line table and fixup in case edits caused
630: * changes in line breaks. If we are breaking on word boundaries,
631: * this code checks for moving words to and from lines.
632: */
633: if (visible) {
634: for (i = line1; i < ctx->text.lt.lines; i++) {/* fixup line table */
635: width = (ctx->text.options & resizeWidth) ? 9999 : ctx->core.width - x;
636: if (startPos <= ctx->text.lastPos) {
637: (*(ctx->text.sink->findPosition))(ctx, startPos, x,
638: width, (ctx->text.options & wordBreak),
639: &endPos, &realW, &realH);
640: if (!(ctx->text.options & wordBreak) && endPos < ctx->text.lastPos) {
641: endPos = (*(ctx->text.source->scan))(ctx->text.source, startPos,
642: XtstEOL, XtsdRight, 1, TRUE);
643: if (endPos == startPos)
644: endPos = ctx->text.lastPos + 1;
645: }
646: ctx->text.lt.info[i].endX = realW + x;
647: ctx->text.lt.info[i + 1].y = realH + ctx->text.lt.info[i].y;
648: if ((endPos > pos1) &&
649: (endPos == ctx->text.lt.info[i + 1].position))
650: break;
651: startPos = endPos;
652: }
653: if (startPos > ctx->text.lastPos)
654: ctx->text.lt.info[i + 1].endX = ctx->text.leftmargin;
655: ctx->text.lt.info[i + 1].position = startPos;
656: x = ctx->text.lt.info[i + 1].x;
657: }
658: }
659: if (delta >= ctx->text.lastPos)
660: endPos = ctx->text.lastPos;
661: if (delta >= ctx->text.lastPos || pos2 >= ctx->text.lt.top)
662: _XtTextNeedsUpdating(ctx, updateFrom, endPos);
663: SetScrollBar(ctx);
664: return error;
665: }
666:
667:
668: /*
669: * This routine will display text between two arbitrary source positions.
670: * In the event that this span contains highlighted text for the selection,
671: * only that portion will be displayed highlighted.
672: */
673: static void DisplayText(ctx, pos1, pos2)
674: TextWidget ctx;
675: XtTextPosition pos1, pos2;
676: /* it is illegal to call this routine unless there is a valid line table!*/
677: {
678: Position x, y;
679: Dimension height;
680: int line, i, visible;
681: XtTextPosition startPos, endPos;
682:
683: if (pos1 < ctx->text.lt.top)
684: pos1 = ctx->text.lt.top;
685: if (pos2 > ctx->text.lastPos)
686: pos2 = ctx->text.lastPos;
687: if (pos1 >= pos2) return;
688: visible = LineAndXYForPosition(ctx, pos1, &line, &x, &y);
689: if (!visible)
690: return;
691: startPos = pos1;
692: height = ctx->text.lt.info[1].y - ctx->text.lt.info[0].y;
693: for (i = line; i < ctx->text.lt.lines; i++) {
694: endPos = ctx->text.lt.info[i + 1].position;
695: if (endPos > pos2)
696: endPos = pos2;
697: if (endPos > startPos) {
698: if (x == ctx->text.leftmargin)
699: (*(ctx->text.sink->clearToBackground))(ctx,
700: 0, y, ctx->text.leftmargin, height);
701: if (startPos >= ctx->text.s.right || endPos <= ctx->text.s.left) {
702: (*(ctx->text.sink->display))(ctx, x, y,
703: startPos, endPos, FALSE);
704: } else if (startPos >= ctx->text.s.left && endPos <= ctx->text.s.right) {
705: (*(ctx->text.sink->display))(ctx, x, y,
706: startPos, endPos, TRUE);
707: } else {
708: DisplayText(ctx, startPos, ctx->text.s.left);
709: DisplayText(ctx, max(startPos, ctx->text.s.left),
710: min(endPos, ctx->text.s.right));
711: DisplayText(ctx, ctx->text.s.right, endPos);
712: }
713: }
714: startPos = endPos;
715: height = ctx->text.lt.info[i + 1].y - ctx->text.lt.info[i].y;
716: (*(ctx->text.sink->clearToBackground))(ctx,
717: ctx->text.lt.info[i].endX, y, 999, height);
718: x = ctx->text.leftmargin;
719: y = ctx->text.lt.info[i + 1].y;
720: if ((endPos == pos2) && (endPos != ctx->text.lastPos))
721: break;
722: }
723: }
724:
725: /*
726: * This routine implements multi-click selection in a hardwired manner.
727: * It supports multi-click entity cycling (char, word, line, file) and mouse
728: * motion adjustment of the selected entitie (i.e. select a word then, with
729: * button still down, adjust wich word you really meant by moving the mouse).
730: * [NOTE: This routine is to be replaced by a set of procedures that
731: * will allows clients to implements a wide class of draw through and
732: * multi-click selection user interfaces.]
733: */
734: static void DoSelection (ctx, position, time, motion)
735: TextWidget ctx;
736: XtTextPosition position;
737: unsigned short time;
738: Boolean motion;
739: {
740: int delta;
741: XtTextPosition newLeft, newRight;
742: XtSelectType newType;
743: XtSelectType *sarray;
744:
745: delta = (time < ctx->text.lasttime) ?
746: ctx->text.lasttime - time : time - ctx->text.lasttime;
747: if (motion)
748: newType = ctx->text.s.type;
749: else {
750: if ((delta < 500) && ((position >= ctx->text.s.left)
751: && (position <= ctx->text.s.right))) { /* multi-click event */
752: sarray = ctx->text.sarray;
753: for (sarray = ctx->text.sarray;
754: *sarray != XtselectNull && *sarray != ctx->text.s.type;
755: sarray++) ;
756: if (*sarray != XtselectNull) sarray++;
757: if (*sarray == XtselectNull) sarray = ctx->text.sarray;
758: newType = *sarray;
759: } else { /* single-click event */
760: newType = *(ctx->text.sarray);
761: }
762: ctx->text.lasttime = time;
763: }
764: switch (newType) {
765: case XtselectPosition:
766: newLeft = newRight = position;
767: break;
768: case XtselectChar:
769: newLeft = position;
770: newRight = (*(ctx->text.source->scan))(
771: ctx->text.source, position, position, XtsdRight, 1, FALSE);
772: break;
773: case XtselectWord:
774: newLeft = (*(ctx->text.source->scan))(
775: ctx->text.source, position, XtstWhiteSpace, XtsdLeft, 1, FALSE);
776: newRight = (*(ctx->text.source->scan))(
777: ctx->text.source, position, XtstWhiteSpace, XtsdRight, 1, FALSE);
778: break;
779: case XtselectLine:
780: case XtselectParagraph: /* need "para" scan mode to implement pargraph */
781: newLeft = (*(ctx->text.source->scan))(
782: ctx->text.source, position, XtstEOL, XtsdLeft, 1, FALSE);
783: newRight = (*(ctx->text.source->scan))(
784: ctx->text.source, position, XtstEOL, XtsdRight, 1, FALSE);
785: break;
786: case XtselectAll:
787: newLeft = (*(ctx->text.source->scan))(
788: ctx->text.source, position, XtstFile, XtsdLeft, 1, FALSE);
789: newRight = (*(ctx->text.source->scan))(
790: ctx->text.source, position, XtstFile, XtsdRight, 1, FALSE);
791: break;
792: }
793: if ((newLeft != ctx->text.s.left) || (newRight != ctx->text.s.right)
794: || (newType != ctx->text.s.type)) {
795: _XtTextSetNewSelection(ctx, newLeft, newRight);
796: ctx->text.s.type = newType;
797: if (position - ctx->text.s.left < ctx->text.s.right - position)
798: ctx->text.insertPos = newLeft;
799: else
800: ctx->text.insertPos = newRight;
801: }
802: if (!motion) { /* setup so we can freely mix select extend calls*/
803: ctx->text.origSel.type = ctx->text.s.type;
804: ctx->text.origSel.left = ctx->text.s.left;
805: ctx->text.origSel.right = ctx->text.s.right;
806: if (position >= ctx->text.s.left + ((ctx->text.s.right - ctx->text.s.left) / 2))
807: ctx->text.extendDir = XtsdRight;
808: else
809: ctx->text.extendDir = XtsdLeft;
810: }
811: }
812:
813: /*
814: * This routine implements extension of the currently selected text in
815: * the "current" mode (i.e. char word, line, etc.). It worries about
816: * extending from either end of the selection and handles the case when you
817: * cross through the "center" of the current selection (e.g. switch which
818: * end you are extending!).
819: * [NOTE: This routine will be replaced by a set of procedures that
820: * will allows clients to implements a wide class of draw through and
821: * multi-click selection user interfaces.]
822: */
823: static void ExtendSelection (ctx, position, motion)
824: TextWidget ctx;
825: XtTextPosition position;
826: Boolean motion;
827: {
828: XtTextPosition newLeft, newRight;
829:
830:
831: if (!motion) { /* setup for extending selection */
832: ctx->text.origSel.type = ctx->text.s.type;
833: ctx->text.origSel.left = ctx->text.s.left;
834: ctx->text.origSel.right = ctx->text.s.right;
835: if (position >= ctx->text.s.left + ((ctx->text.s.right - ctx->text.s.left) / 2))
836: ctx->text.extendDir = XtsdRight;
837: else
838: ctx->text.extendDir = XtsdLeft;
839: }
840: else /* check for change in extend direction */
841: if ((ctx->text.extendDir == XtsdRight && position < ctx->text.origSel.left) ||
842: (ctx->text.extendDir == XtsdLeft && position > ctx->text.origSel.right)) {
843: ctx->text.extendDir = (ctx->text.extendDir == XtsdRight)? XtsdLeft : XtsdRight;
844: _XtTextSetNewSelection(ctx, ctx->text.origSel.left, ctx->text.origSel.right);
845: }
846: newLeft = ctx->text.s.left;
847: newRight = ctx->text.s.right;
848: switch (ctx->text.s.type) {
849: case XtselectPosition:
850: if (ctx->text.extendDir == XtsdRight)
851: newRight = position;
852: else
853: newLeft = position;
854: break;
855: case XtselectWord:
856: if (ctx->text.extendDir == XtsdRight)
857: newRight = position = (*(ctx->text.source->scan))(
858: ctx->text.source, position, XtstWhiteSpace, XtsdRight, 1, FALSE);
859: else
860: newLeft = position = (*(ctx->text.source->scan))(
861: ctx->text.source, position, XtstWhiteSpace, XtsdLeft, 1, FALSE);
862: break;
863: case XtselectLine:
864: case XtselectParagraph: /* need "para" scan mode to implement pargraph */
865: if (ctx->text.extendDir == XtsdRight)
866: newRight = position = (*(ctx->text.source->scan))(
867: ctx->text.source, position, XtstEOL, XtsdRight, 1, TRUE);
868: else
869: newLeft = position = (*(ctx->text.source->scan))(
870: ctx->text.source, position, XtstEOL, XtsdLeft, 1, FALSE);
871: break;
872: case XtselectAll:
873: position = ctx->text.insertPos;
874: break;
875: }
876: _XtTextSetNewSelection(ctx, newLeft, newRight);
877: ctx->text.insertPos = position;
878: }
879:
880:
881: /*
882: * Clear the window to background color.
883: */
884: static ClearWindow (ctx)
885: TextWidget ctx;
886: {
887: (*(ctx->text.sink->clearToBackground))(ctx, 0, 0, ctx->core.width, ctx->core.height);
888: }
889:
890:
891: /*
892: * Internal redisplay entire window.
893: */
894: DisplayTextWindow (w)
895: Widget w;
896: {
897: TextWidget ctx = (TextWidget) w;
898: ClearWindow(ctx);
899: BuildLineTable(ctx, ctx->text.lt.top);
900: _XtTextNeedsUpdating(ctx, zeroPosition, ctx->text.lastPos);
901: SetScrollBar(ctx);
902: }
903:
904: /*
905: * This routine checks to see if the window should be resized (grown or
906: * shrunk) or scrolled then text to be painted overflows to the right or
907: * the bottom of the window. It is used by the keyboard input routine.
908: */
909: CheckResizeOrOverflow(ctx)
910: TextWidget ctx;
911: {
912: XtTextPosition posToCheck;
913: int visible, line, width;
914: XtWidgetGeometry rbox;
915: if (ctx->text.options & resizeWidth) {
916: width = 0;
917: for (line=0 ; line<ctx->text.lt.lines ; line++)
918: if (width < ctx->text.lt.info[line].endX)
919: width = ctx->text.lt.info[line].endX;
920: width += ctx->text.leftmargin;
921: if (width > ctx->core.width) {
922: rbox.request_mode = CWWidth;
923: rbox.width = width;
924: if ( XtMakeGeometryRequest(ctx, &rbox, NULL) != XtGeometryNo) {
925: ctx->core.width = rbox.width;
926: }
927: }
928: }
929: if ((ctx->text.options & resizeHeight) || (ctx->text.options & scrollOnOverflow)) {
930: if (ctx->text.options & scrollOnOverflow)
931: posToCheck = ctx->text.insertPos;
932: else
933: posToCheck = ctx->text.lastPos;
934: visible = IsPositionVisible(ctx, posToCheck);
935: if (visible)
936: line = LineForPosition(ctx, posToCheck);
937: else
938: line = ctx->text.lt.lines;
939: if ((ctx->text.options & scrollOnOverflow) && (line + 1 > ctx->text.lt.lines)) {
940: BuildLineTable(ctx, ctx->text.lt.info[1].position);
941: XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx),
942: ctx->text.gc, (Position)ctx->text.leftmargin,
943: ctx->text.lt.info[1].y, 9999, 9999,
944: (Position)ctx->text.leftmargin, ctx->text.lt.info[0].y);
945: }
946: else
947: if ((ctx->text.options & resizeHeight) && (line + 1 != ctx->text.lt.lines)) {
948: rbox.request_mode = CWHeight;
949: rbox.height = (*(ctx->text.sink->maxHeight))
950: (ctx, line + 1) + (2*yMargin)+2;
951: if (XtMakeGeometryRequest(ctx, &rbox, NULL) != XtGeometryNo) {
952: ctx->core.width = rbox.height ;
953: };
954: }
955: }
956: }
957:
958: /*
959: * This routine is used to perform various selection functions. The goal is
960: * to be able to specify all the more popular forms of draw-through and
961: * multi-click selection user interfaces from the outside.
962: */
963: void AlterSelection (ctx, mode, action)
964: TextWidget ctx;
965: SelectionMode mode; /* {XtsmTextSelect, XtsmTextExtend} */
966: SelectionAction action; /* {XtactionStart, XtactionAdjust, XtactionEnd} */
967: {
968: XtTextPosition position;
969: char *ptr;
970:
971: position = PositionForXY (ctx, (int) ctx->text.ev_x, (int) ctx->text.ev_y);
972: if (action == XtactionStart) {
973: switch (mode) {
974: case XtsmTextSelect:
975: DoSelection (ctx, position, ctx->text.time, FALSE);
976: break;
977: case XtsmTextExtend:
978: ExtendSelection (ctx, position, FALSE);
979: break;
980: }
981: }
982: else {
983: switch (mode) {
984: case XtsmTextSelect:
985: DoSelection (ctx, position, ctx->text.time, TRUE);
986: break;
987: case XtsmTextExtend:
988: ExtendSelection (ctx, position, TRUE);
989: break;
990: }
991: }
992: if (action == XtactionEnd && ctx->text.s.left < ctx->text.s.right) {
993: ptr = _XtTextGetText (ctx, ctx->text.s.left, ctx->text.s.right);
994: XStoreBuffer (XtDisplay(ctx), ptr, min (strlen (ptr), MAXCUT), 0);
995: XtFree (ptr);
996: }
997: }
998:
999: /*
1000: * This routine processes all "expose region" XEvents. In general, its job
1001: * is to the best job at minimal re-paint of the text, displayed in the
1002: * window, that it can.
1003: */
1004: static void ProcessExposeRegion(w, event)
1005: Widget w;
1006: XEvent *event;
1007: {
1008: TextWidget ctx = (TextWidget) w;
1009: XtTextPosition pos1, pos2, resultend;
1010: int line;
1011: int x = event->xexpose.x;
1012: int y = event->xexpose.y;
1013: int width = event->xexpose.width;
1014: int height = event->xexpose.height;
1015: LineTableEntryPtr info;
1016:
1017: _XtTextPrepareToUpdate(ctx);
1018: if (x < ctx->text.leftmargin) /* stomp on caret tracks */
1019: (*(ctx->text.sink->clearToBackground))(ctx, x, y, width, height);
1020: /* figure out starting line that was exposed */
1021: line = LineForPosition(ctx, PositionForXY(ctx, x, y));
1022: while (line < ctx->text.lt.lines && ctx->text.lt.info[line + 1].y < y)
1023: line++;
1024: while (line < ctx->text.lt.lines) {
1025: info = &(ctx->text.lt.info[line]);
1026: if (info->y >= y + height)
1027: break;
1028: (*(ctx->text.sink->resolve))(ctx,
1029: info->position, info->x,
1030: x - info->x, &pos1, &resultend);
1031: (*(ctx->text.sink->resolve))(ctx,
1032: info->position, info->x,
1033: x + width - info->x, &pos2,
1034: &resultend);
1035: pos2 = (*(ctx->text.source->scan))(ctx->text.source, pos2, XtstPositions,
1036: XtsdRight, 1, TRUE);
1037: _XtTextNeedsUpdating(ctx, pos1, pos2);
1038: line++;
1039: }
1040: _XtTextExecuteUpdate(ctx);
1041: }
1042:
1043:
1044: static int oldinsert = -1;
1045:
1046: /*
1047: * This routine does all setup required to syncronize batched screen updates
1048: */
1049: int _XtTextPrepareToUpdate(ctx)
1050: TextWidget ctx;
1051: {
1052: if (oldinsert < 0) {
1053: InsertCursor(ctx, XtisOff);
1054: ctx->text.numranges = 0;
1055: ctx->text.showposition = FALSE;
1056: oldinsert = ctx->text.insertPos;
1057: }
1058: }
1059:
1060:
1061: /*
1062: * This is a private utility routine used by _XtTextExecuteUpdate. It
1063: * processes all the outstanding update requests and merges update
1064: * ranges where possible.
1065: */
1066: static FlushUpdate(ctx)
1067: TextWidget ctx;
1068: {
1069: int i, w;
1070: XtTextPosition updateFrom, updateTo;
1071: while (ctx->text.numranges > 0) {
1072: updateFrom = ctx->text.updateFrom[0];
1073: w = 0;
1074: for (i=1 ; i<ctx->text.numranges ; i++) {
1075: if (ctx->text.updateFrom[i] < updateFrom) {
1076: updateFrom = ctx->text.updateFrom[i];
1077: w = i;
1078: }
1079: }
1080: updateTo = ctx->text.updateTo[w];
1081: ctx->text.numranges--;
1082: ctx->text.updateFrom[w] = ctx->text.updateFrom[ctx->text.numranges];
1083: ctx->text.updateTo[w] = ctx->text.updateTo[ctx->text.numranges];
1084: for (i=ctx->text.numranges-1 ; i>=0 ; i--) {
1085: while (ctx->text.updateFrom[i] <= updateTo && i < ctx->text.numranges) {
1086: updateTo = ctx->text.updateTo[i];
1087: ctx->text.numranges--;
1088: ctx->text.updateFrom[i] = ctx->text.updateFrom[ctx->text.numranges];
1089: ctx->text.updateTo[i] = ctx->text.updateTo[ctx->text.numranges];
1090: }
1091: }
1092: DisplayText(ctx, updateFrom, updateTo);
1093: }
1094: }
1095:
1096:
1097: /*
1098: * This is a private utility routine used by _XtTextExecuteUpdate. This routine
1099: * worries about edits causing new data or the insertion point becoming
1100: * invisible (off the screen). Currently it always makes it visible by
1101: * scrolling. It probably needs generalization to allow more options.
1102: */
1103: _XtTextShowPosition(ctx)
1104: TextWidget ctx;
1105: {
1106: XtTextPosition top, first, second;
1107: if (ctx->text.insertPos < ctx->text.lt.top ||
1108: ctx->text.insertPos >= ctx->text.lt.info[ctx->text.lt.lines].position) {
1109: if (ctx->text.lt.lines > 0 && (ctx->text.insertPos < ctx->text.lt.top
1110: || ctx->text.lt.info[ctx->text.lt.lines].position <= ctx->text.lastPos)) {
1111: first = ctx->text.lt.top;
1112: second = ctx->text.lt.info[1].position;
1113: if (ctx->text.insertPos < first)
1114: top = (*(ctx->text.source->scan))(
1115: ctx->text.source, ctx->text.insertPos, XtstEOL,
1116: XtsdLeft, 1, FALSE);
1117: else
1118: top = (*(ctx->text.source->scan))(
1119: ctx->text.source, ctx->text.insertPos, XtstEOL,
1120: XtsdLeft, ctx->text.lt.lines, FALSE);
1121: BuildLineTable(ctx, top);
1122: while (ctx->text.insertPos >= ctx->text.lt.info[ctx->text.lt.lines].position) {
1123: if (ctx->text.lt.info[ctx->text.lt.lines].position > ctx->text.lastPos)
1124: break;
1125: BuildLineTable(ctx, ctx->text.lt.info[1].position);
1126: }
1127: if (ctx->text.lt.top == second) {
1128: BuildLineTable(ctx, first);
1129: _XtTextScroll(ctx, 1);
1130: } else if (ctx->text.lt.info[1].position == first) {
1131: BuildLineTable(ctx, first);
1132: _XtTextScroll(ctx, -1);
1133: } else {
1134: ctx->text.numranges = 0;
1135: if (ctx->text.lt.top != first)
1136: DisplayTextWindow(ctx);
1137: }
1138: }
1139: }
1140: }
1141:
1142:
1143:
1144: /*
1145: * This routine causes all batched screen updates to be performed
1146: */
1147: _XtTextExecuteUpdate(ctx)
1148: TextWidget ctx;
1149: {
1150: if (oldinsert >= 0) {
1151: if (oldinsert != ctx->text.insertPos || ctx->text.showposition)
1152: _XtTextShowPosition(ctx);
1153: FlushUpdate(ctx);
1154: InsertCursor(ctx, XtisOn);
1155: oldinsert = -1;
1156: }
1157: }
1158:
1159:
1160: static void TextDestroy(ctx)
1161: TextWidget ctx;
1162: {
1163: if (ctx->text.dialog)
1164: (void) XtDestroyWidget(ctx->text.dialog);
1165: if (ctx->text.outer)
1166: (void) XtDestroyWidget(ctx->text.outer);
1167: if (ctx->text.sbar)
1168: (void) XtDestroyWidget(ctx->text.sbar);
1169: XtFree((char *)ctx->text.updateFrom);
1170: XtFree((char *)ctx->text.updateTo);
1171: }
1172:
1173:
1174: static void Resize(w)
1175: Widget w;
1176: {
1177: TextWidget ctx = (TextWidget) w;
1178: _XtTextPrepareToUpdate(ctx);
1179: ForceBuildLineTable(ctx);
1180: _XtTextExecuteUpdate(ctx);
1181: }
1182:
1183:
1184: /*
1185: * This routine allow the application program to Set attributes.
1186: */
1187:
1188: Boolean XtTextSetValues(current, request, new, last)
1189: Widget current, request, new;
1190: Boolean last;
1191: {
1192: TextWidget oldtw = (TextWidget) current;
1193: TextWidget newtw = (TextWidget) new;
1194: Boolean redisplay = FALSE;
1195:
1196: _XtTextPrepareToUpdate(oldtw);
1197:
1198: if (oldtw->text.sink != newtw->text.sink)
1199: redisplay = TRUE;
1200:
1201: if (oldtw->text.source != newtw->text.source) {
1202: ForceBuildLineTable(oldtw);
1203: redisplay = TRUE;
1204: }
1205: if (oldtw->text.insertPos != newtw->text.insertPos)
1206: oldtw->text.showposition = TRUE;
1207:
1208: if (oldtw->text.lt.top != newtw->text.lt.top)
1209: redisplay = TRUE;
1210:
1211: if (oldtw->text.leftmargin != newtw->text.leftmargin)
1212: redisplay = TRUE;
1213:
1214: if (redisplay)
1215: DisplayTextWindow(oldtw);
1216: _XtTextExecuteUpdate(oldtw);
1217: return (FALSE); /* this needs looking at! */
1218: }
1219:
1220:
1221:
1222: void XtTextDisplay (w)
1223: Widget w;
1224: {
1225: TextWidget ctx = (TextWidget) w;;
1226:
1227: _XtTextPrepareToUpdate(ctx);
1228: DisplayTextWindow(ctx);
1229: _XtTextExecuteUpdate(ctx);
1230: }
1231:
1232: /*******************************************************************
1233: The following routines provide procedural interfaces to Text window state
1234: setting and getting. They need to be redone so than the args code can use
1235: them. I suggest we create a complete set that takes the context as an
1236: argument and then have the public version lookup the context and call the
1237: internal one. The major value of this set is that they have actual application
1238: clients and therefore the functionality provided is required for any future
1239: version of Text.
1240: ********************************************************************/
1241:
1242: void XtTextSetSelectionArray(w, sarray)
1243: Widget w;
1244: XtSelectType *sarray;
1245: {
1246: TextWidget ctx = (TextWidget) w;
1247: XtSelectType *s2;
1248:
1249: s2 = ctx->text.sarray;
1250: while (XtselectNull != (*s2++ = *sarray++)) ;
1251: }
1252:
1253: void XtTextSetLastPos (w, lastPos)
1254: Widget w;
1255: XtTextPosition lastPos;
1256: {
1257: TextWidget ctx = (TextWidget) w;
1258:
1259: _XtTextPrepareToUpdate(ctx);
1260: (*(ctx->text.source->setLastPos))(ctx->text.source, lastPos);
1261: ctx->text.lastPos = GETLASTPOS;
1262: ForceBuildLineTable(ctx);
1263: DisplayTextWindow(ctx);
1264: _XtTextExecuteUpdate(ctx);
1265: }
1266:
1267:
1268: void XtTextGetSelectionPos(w, left, right)
1269: Widget w;
1270: XtTextPosition *left, *right;
1271: {
1272: TextWidget ctx = (TextWidget) w;
1273: *left = ctx->text.s.left;
1274: *right = ctx->text.s.right;
1275: }
1276:
1277:
1278: void XtTextNewSource(w, source, startPos)
1279: Widget w;
1280: XtTextSource *source;
1281: XtTextPosition startPos;
1282: {
1283: TextWidget ctx = (TextWidget) w;
1284:
1285: ctx->text.source = source;
1286: ctx->text.lt.top = startPos;
1287: ctx->text.s.left = ctx->text.s.right = 0;
1288: ctx->text.insertPos = startPos;
1289: ctx->text.lastPos = GETLASTPOS;
1290: ForceBuildLineTable(ctx);
1291: _XtTextPrepareToUpdate(ctx);
1292: DisplayTextWindow(ctx);
1293: _XtTextExecuteUpdate(ctx);
1294: }
1295:
1296: /*
1297: * This public routine deletes the text from startPos to endPos in a source and
1298: * then inserts, at startPos, the text that was passed. As a side effect it
1299: * "invalidates" that portion of the displayed text (if any), so that things
1300: * will be repainted properly.
1301: */
1302: int XtTextReplace(w, startPos, endPos, text)
1303: Widget w;
1304: XtTextPosition startPos, endPos;
1305: XtTextBlock *text;
1306: {
1307: TextWidget ctx = (TextWidget) w;
1308: int result;
1309: result = EDITERROR;
1310: _XtTextPrepareToUpdate(ctx);
1311: result = ReplaceText(ctx, startPos, endPos, text);
1312: _XtTextExecuteUpdate(ctx);
1313: return result;
1314: }
1315:
1316:
1317: XtTextPosition XtTextTopPosition(w)
1318: Widget w;
1319: {
1320: TextWidget ctx = (TextWidget) w;
1321:
1322: return ctx->text.lt.top;
1323: }
1324:
1325:
1326: void XtTextSetInsertionPoint(w, position)
1327: Widget w;
1328: XtTextPosition position;
1329: {
1330: TextWidget ctx = (TextWidget) w;
1331:
1332: _XtTextPrepareToUpdate(ctx);
1333: ctx->text.insertPos = position;
1334: ctx->text.showposition = TRUE;
1335: _XtTextExecuteUpdate(ctx);
1336: }
1337:
1338:
1339: XtTextPosition XtTextGetInsertionPoint(w)
1340: Widget w;
1341: {
1342: TextWidget ctx = (TextWidget) w;
1343:
1344: return(ctx->text.insertPos);
1345: }
1346:
1347:
1348: void XtTextUnsetSelection(w)
1349: Widget w;
1350: {
1351: TextWidget ctx = (TextWidget) w;
1352:
1353: _XtTextPrepareToUpdate(ctx);
1354: _XtTextSetNewSelection(ctx, zeroPosition, zeroPosition);
1355: _XtTextExecuteUpdate(ctx);
1356: }
1357:
1358:
1359: void XtTextChangeOptions(w, options)
1360: Widget w;
1361: int options;
1362: {
1363: TextWidget ctx = (TextWidget) w;
1364:
1365: ctx->text.options = options;
1366: }
1367:
1368:
1369: int XtTextGetOptions(w)
1370: Widget w;
1371: {
1372: TextWidget ctx = (TextWidget) w;
1373:
1374: return ctx->text.options;
1375: }
1376:
1377: void XtTextSetNewSelection (w, left, right)
1378: Widget w;
1379: XtTextPosition left, right;
1380: {
1381: TextWidget ctx = (TextWidget) w;
1382:
1383: _XtTextPrepareToUpdate(ctx);
1384: _XtTextSetNewSelection(ctx, left, right);
1385: _XtTextExecuteUpdate(ctx);
1386: }
1387:
1388: void XtTextInvalidate(w, from, to)
1389: Widget w;
1390: XtTextPosition from,to;
1391: {
1392: TextWidget ctx = (TextWidget) w;
1393:
1394: ctx->text.lastPos = (*(ctx->text.source->getLastPos))(ctx->text.source);
1395: _XtTextPrepareToUpdate(ctx);
1396: _XtTextNeedsUpdating(ctx, from, to);
1397: ForceBuildLineTable(ctx);
1398: _XtTextExecuteUpdate(ctx);
1399: }
1400:
1401:
1402: /* Returns the window actually containing the text (which is not the same
1403: as the given window if the text window has scrollbars.) */
1404:
1405: Window XtTextGetInnerWindow(w)
1406: Widget w;
1407: {
1408: TextWidget ctx = (TextWidget) w;
1409: return XtWindow(ctx);
1410: }
1411:
1412: /* The following used to be a separate file, TextActs.c, but
1413: is included here because textActionsTable can't be external
1414: to the file declaring textClassRec */
1415:
1416: /* Misc. routines */
1417: void TextAcceptFocus(w)
1418: Widget w;
1419: {
1420: TextWidget ctx = (TextWidget) w;
1421: if (!ctx->text.hasfocus)
1422: XSetInputFocus(XtDisplay(ctx), XtWindow(ctx),
1423: RevertToPointerRoot, CurrentTime);
1424: }
1425:
1426: static StartAction(ctx, event)
1427: TextWidget ctx;
1428: XEvent *event;
1429: {
1430: _XtTextPrepareToUpdate(ctx);
1431: if (event->type == ButtonPress) TextAcceptFocus(ctx);
1432: /* this code is wrong if actions bound to non-button events! */
1433: ctx->text.time = event->xbutton.time;
1434: ctx->text.ev_x = event->xbutton.x;
1435: ctx->text.ev_y = event->xbutton.y;
1436: }
1437:
1438: static EndAction(ctx)
1439: TextWidget ctx;
1440: {
1441: CheckResizeOrOverflow(ctx);
1442: _XtTextExecuteUpdate(ctx);
1443: }
1444:
1445: /*ARGSUSED*/
1446: static DoFeep(ctx)
1447: TextWidget ctx;
1448: {
1449: XBell(XtDisplay(ctx), 50);
1450: }
1451:
1452: static DeleteOrKill(ctx, from, to, kill)
1453: TextWidget ctx;
1454: XtTextPosition from, to;
1455: Boolean kill;
1456: {
1457: XtTextBlock text;
1458: char *ptr;
1459:
1460: if (kill && from < to) {
1461: ptr = _XtTextGetText(ctx, from, to);
1462: XStoreBuffer(XtDisplay(ctx), ptr, strlen(ptr), 1);
1463: XtFree(ptr);
1464: }
1465: text.length = 0;
1466: if (ReplaceText(ctx, from, to, &text)) {
1467: XBell(XtDisplay(ctx), 50);
1468: return;
1469: }
1470: _XtTextSetNewSelection(ctx, from, from);
1471: ctx->text.insertPos = from;
1472: ctx->text.showposition = TRUE;
1473: }
1474:
1475:
1476: StuffFromBuffer(ctx, buffer)
1477: TextWidget ctx;
1478: int buffer;
1479: {
1480: extern char *XFetchBuffer();
1481: XtTextBlock text;
1482: text.ptr = XFetchBuffer(XtDisplay(ctx), &(text.length), buffer);
1483: if (ReplaceText(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) {
1484: XBell(XtDisplay(ctx), 50);
1485: return;
1486: }
1487: ctx->text.insertPos = ctx->text.source->scan(ctx->text.source,
1488: ctx->text.insertPos, XtstPositions, XtsdRight, text.length, TRUE);
1489: _XtTextSetNewSelection(ctx, ctx->text.insertPos, ctx->text.insertPos);
1490: XtFree(text.ptr);
1491: }
1492:
1493:
1494: static UnKill(ctx, event)
1495: TextWidget ctx;
1496: XEvent *event;
1497: {
1498: StartAction(ctx, event);
1499: StuffFromBuffer(ctx, 1);
1500: EndAction(ctx);
1501: }
1502:
1503: static Stuff(ctx, event)
1504: TextWidget ctx;
1505: XEvent *event;
1506: {
1507: StartAction(ctx, event);
1508: StuffFromBuffer(ctx, 0);
1509: EndAction(ctx);
1510: }
1511:
1512:
1513: static XtTextPosition NextPosition(ctx, position, kind, direction)
1514: TextWidget ctx;
1515: XtTextPosition position;
1516: ScanType kind;
1517: ScanDirection direction;
1518: {
1519: XtTextPosition pos;
1520:
1521: pos = ctx->text.source->scan(
1522: ctx->text.source, position, kind, direction, 1, FALSE);
1523: if (pos == ctx->text.insertPos)
1524: pos = ctx->text.source->scan(
1525: ctx->text.source, position, kind, direction, 2, FALSE);
1526: return pos;
1527: }
1528:
1529: /* routines for moving around */
1530:
1531: static MoveForwardChar(ctx, event)
1532: TextWidget ctx;
1533: XEvent *event;
1534: {
1535: StartAction(ctx, event);
1536: ctx->text.insertPos = ctx->text.source->scan(
1537: ctx->text.source, ctx->text.insertPos, XtstPositions, XtsdRight, 1,
1538: TRUE);
1539: EndAction(ctx);
1540: }
1541:
1542: static MoveBackwardChar(ctx, event)
1543: TextWidget ctx;
1544: XEvent *event;
1545: {
1546: StartAction(ctx, event);
1547: ctx->text.insertPos = ctx->text.source->scan(
1548: ctx->text.source, ctx->text.insertPos, XtstPositions, XtsdLeft,
1549: 1, TRUE);
1550: EndAction(ctx);
1551: }
1552:
1553: static MoveForwardWord(ctx, event)
1554: TextWidget ctx;
1555: XEvent *event;
1556: {
1557: StartAction(ctx, event);
1558: ctx->text.insertPos = NextPosition(ctx, ctx->text.insertPos,
1559: XtstWhiteSpace, XtsdRight);
1560: EndAction(ctx);
1561: }
1562:
1563: static MoveBackwardWord(ctx, event)
1564: TextWidget ctx;
1565: XEvent *event;
1566: {
1567: StartAction(ctx, event);
1568: ctx->text.insertPos = NextPosition(ctx, ctx->text.insertPos,
1569: XtstWhiteSpace, XtsdLeft);
1570: EndAction(ctx);
1571: }
1572:
1573: static MoveBackwardParagraph(ctx, event)
1574: TextWidget ctx;
1575: XEvent *event;
1576: {
1577: StartAction(ctx, event);
1578: ctx->text.insertPos = NextPosition(ctx, ctx->text.insertPos,
1579: XtstEOL, XtsdLeft);
1580: EndAction(ctx);
1581: }
1582:
1583: static MoveForwardParagraph(ctx, event)
1584: TextWidget ctx;
1585: XEvent *event;
1586: {
1587: StartAction(ctx, event);
1588: ctx->text.insertPos = NextPosition(ctx, ctx->text.insertPos,
1589: XtstEOL, XtsdRight);
1590: EndAction(ctx);
1591: }
1592:
1593:
1594: static MoveToLineStart(ctx, event)
1595: TextWidget ctx;
1596: XEvent *event;
1597: {
1598: int line;
1599: StartAction(ctx, event);
1600: _XtTextShowPosition(ctx);
1601: line = LineForPosition(ctx, ctx->text.insertPos);
1602: ctx->text.insertPos = ctx->text.lt.info[line].position;
1603: EndAction(ctx);
1604: }
1605:
1606: static MoveToLineEnd(ctx, event)
1607: TextWidget ctx;
1608: XEvent *event;
1609: {
1610: int line;
1611: XtTextPosition next;
1612: StartAction(ctx, event);
1613: _XtTextShowPosition(ctx);
1614: line = LineForPosition(ctx, ctx->text.insertPos);
1615: next = ctx->text.lt.info[line+1].position;
1616: if (next > ctx->text.lastPos)
1617: next = ctx->text.lastPos;
1618: else
1619: next = ctx->text.source->scan(ctx->text.source, next, XtstPositions,
1620: XtsdLeft, 1, TRUE);
1621: ctx->text.insertPos = next;
1622: EndAction(ctx);
1623: }
1624:
1625:
1626: static int LineLastWidth = 0;
1627: static XtTextPosition LineLastPosition = 0;
1628:
1629: static MoveNextLine(ctx, event)
1630: TextWidget ctx;
1631: XEvent *event;
1632: {
1633: int width, width2, height, line;
1634: XtTextPosition position, maxp;
1635: StartAction(ctx, event);
1636: _XtTextShowPosition(ctx);
1637: line = LineForPosition(ctx, ctx->text.insertPos);
1638: if (line == ctx->text.lt.lines - 1) {
1639: _XtTextScroll(ctx, 1);
1640: line = LineForPosition(ctx, ctx->text.insertPos);
1641: }
1642: if (LineLastPosition == ctx->text.insertPos)
1643: width = LineLastWidth;
1644: else
1645: ctx->text.sink->findDistance(ctx,
1646: ctx->text.lt.info[line].position, ctx->text.lt.info[line].x,
1647: ctx->text.insertPos, &width, &position, &height);
1648: line++;
1649: if (ctx->text.lt.info[line].position > ctx->text.lastPos) {
1650: ctx->text.insertPos = ctx->text.lastPos;
1651: EndAction(ctx);
1652: return;
1653: }
1654: ctx->text.sink->findPosition(ctx,
1655: ctx->text.lt.info[line].position, ctx->text.lt.info[line].x,
1656: width, FALSE, &position, &width2, &height);
1657: maxp = ctx->text.source->scan(ctx->text.source,
1658: ctx->text.lt.info[line+1].position,
1659: XtstPositions, XtsdLeft, 1, TRUE);
1660: if (position > maxp)
1661: position = maxp;
1662: ctx->text.insertPos = position;
1663: LineLastWidth = width;
1664: LineLastPosition = position;
1665: EndAction(ctx);
1666: }
1667:
1668: static MovePreviousLine(ctx, event)
1669: TextWidget ctx;
1670: XEvent *event;
1671: {
1672: int width, width2, height, line;
1673: XtTextPosition position, maxp;
1674: StartAction(ctx, event);
1675: _XtTextShowPosition(ctx);
1676: line = LineForPosition(ctx, ctx->text.insertPos);
1677: if (line == 0) {
1678: _XtTextScroll(ctx, -1);
1679: line = LineForPosition(ctx, ctx->text.insertPos);
1680: }
1681: if (line > 0) {
1682: if (LineLastPosition == ctx->text.insertPos)
1683: width = LineLastWidth;
1684: else
1685: ctx->text.sink->findDistance(ctx,
1686: ctx->text.lt.info[line].position,
1687: ctx->text.lt.info[line].x,
1688: ctx->text.insertPos, &width, &position, &height);
1689: line--;
1690: ctx->text.sink->findPosition(ctx,
1691: ctx->text.lt.info[line].position, ctx->text.lt.info[line].x,
1692: width, FALSE, &position, &width2, &height);
1693: maxp = ctx->text.source->scan(ctx->text.source,
1694: ctx->text.lt.info[line+1].position,
1695: XtstPositions, XtsdLeft, 1, TRUE);
1696: if (position > maxp)
1697: position = maxp;
1698: ctx->text.insertPos = position;
1699: LineLastWidth = width;
1700: LineLastPosition = position;
1701: }
1702: EndAction(ctx);
1703: }
1704:
1705:
1706:
1707: static MoveBeginningOfFile(ctx, event)
1708: TextWidget ctx;
1709: XEvent *event;
1710: {
1711: StartAction(ctx, event);
1712: ctx->text.insertPos = ctx->text.source->scan(ctx->text.source,
1713: ctx->text.insertPos, XtstFile, XtsdLeft, 1, TRUE);
1714: EndAction(ctx);
1715: }
1716:
1717:
1718: static MoveEndOfFile(ctx, event)
1719: TextWidget ctx;
1720: XEvent *event;
1721: {
1722: StartAction(ctx, event);
1723: ctx->text.insertPos = ctx->text.source->scan(ctx->text.source,
1724: ctx->text.insertPos, XtstFile, XtsdRight, 1, TRUE);
1725: EndAction(ctx);
1726: }
1727:
1728: static ScrollOneLineUp(ctx, event)
1729: TextWidget ctx;
1730: XEvent *event;
1731: {
1732: StartAction(ctx, event);
1733: _XtTextScroll(ctx, 1);
1734: EndAction(ctx);
1735: }
1736:
1737: static ScrollOneLineDown(ctx, event)
1738: TextWidget ctx;
1739: XEvent *event;
1740: {
1741: StartAction(ctx, event);
1742: _XtTextScroll(ctx, -1);
1743: EndAction(ctx);
1744: }
1745:
1746: static MoveNextPage(ctx, event)
1747: TextWidget ctx;
1748: XEvent *event;
1749: {
1750: StartAction(ctx, event);
1751: _XtTextScroll(ctx, max(1, ctx->text.lt.lines - 2));
1752: ctx->text.insertPos = ctx->text.lt.top;
1753: EndAction(ctx);
1754: }
1755:
1756: static MovePreviousPage(ctx, event)
1757: TextWidget ctx;
1758: XEvent *event;
1759: {
1760: StartAction(ctx, event);
1761: _XtTextScroll(ctx, -max(1, ctx->text.lt.lines - 2));
1762: ctx->text.insertPos = ctx->text.lt.top;
1763: EndAction(ctx);
1764: }
1765:
1766:
1767:
1768:
1769: /* delete routines */
1770:
1771: static DeleteForwardChar(ctx, event)
1772: TextWidget ctx;
1773: XEvent *event;
1774: {
1775: XtTextPosition next;
1776:
1777: StartAction(ctx, event);
1778: next = ctx->text.source->scan(
1779: ctx->text.source, ctx->text.insertPos, XtstPositions,
1780: XtsdRight, 1, TRUE);
1781: DeleteOrKill(ctx, ctx->text.insertPos, next, FALSE);
1782: EndAction(ctx);
1783: }
1784:
1785: static DeleteBackwardChar(ctx, event)
1786: TextWidget ctx;
1787: XEvent *event;
1788: {
1789: XtTextPosition next;
1790:
1791: StartAction(ctx, event);
1792: next = ctx->text.source->scan(
1793: ctx->text.source, ctx->text.insertPos, XtstPositions,
1794: XtsdLeft, 1, TRUE);
1795: DeleteOrKill(ctx, next, ctx->text.insertPos, FALSE);
1796: EndAction(ctx);
1797: }
1798:
1799: static DeleteForwardWord(ctx, event)
1800: TextWidget ctx;
1801: XEvent *event;
1802: {
1803: XtTextPosition next;
1804:
1805: StartAction(ctx, event);
1806: next = NextPosition(ctx, ctx->text.insertPos, XtstWhiteSpace, XtsdRight);
1807: DeleteOrKill(ctx, ctx->text.insertPos, next, FALSE);
1808: EndAction(ctx);
1809: }
1810:
1811: static DeleteBackwardWord(ctx, event)
1812: TextWidget ctx;
1813: XEvent *event;
1814: {
1815: XtTextPosition next;
1816:
1817: StartAction(ctx, event);
1818: next = NextPosition(ctx, ctx->text.insertPos, XtstWhiteSpace, XtsdLeft);
1819: DeleteOrKill(ctx, next, ctx->text.insertPos, FALSE);
1820: EndAction(ctx);
1821: }
1822:
1823: static KillForwardWord(ctx, event)
1824: TextWidget ctx;
1825: XEvent *event;
1826: {
1827: XtTextPosition next;
1828:
1829: StartAction(ctx, event);
1830: next = NextPosition(ctx, ctx->text.insertPos, XtstWhiteSpace, XtsdRight);
1831: DeleteOrKill(ctx, ctx->text.insertPos, next, TRUE);
1832: EndAction(ctx);
1833: }
1834:
1835: static KillBackwardWord(ctx, event)
1836: TextWidget ctx;
1837: XEvent *event;
1838: {
1839: XtTextPosition next;
1840:
1841: StartAction(ctx, event);
1842: next = NextPosition(ctx, ctx->text.insertPos, XtstWhiteSpace, XtsdLeft);
1843: DeleteOrKill(ctx, next, ctx->text.insertPos, TRUE);
1844: EndAction(ctx);
1845: }
1846:
1847: static KillCurrentSelection(ctx, event)
1848: TextWidget ctx;
1849: XEvent *event;
1850: {
1851: StartAction(ctx, event);
1852: DeleteOrKill(ctx, ctx->text.s.left, ctx->text.s.right, TRUE);
1853: EndAction(ctx);
1854: }
1855:
1856: static DeleteCurrentSelection(ctx, event)
1857: TextWidget ctx;
1858: XEvent *event;
1859: {
1860: StartAction(ctx, event);
1861: DeleteOrKill(ctx, ctx->text.s.left, ctx->text.s.right, FALSE);
1862: EndAction(ctx);
1863: }
1864:
1865: static KillToEndOfLine(ctx, event)
1866: TextWidget ctx;
1867: XEvent *event;
1868: {
1869: int line;
1870: XtTextPosition last, next;
1871: StartAction(ctx, event);
1872: _XtTextShowPosition(ctx);
1873: line = LineForPosition(ctx, ctx->text.insertPos);
1874: last = ctx->text.lt.info[line + 1].position;
1875: next = ctx->text.source->scan(ctx->text.source, ctx->text.insertPos,
1876: XtstEOL, XtsdRight, 1, FALSE);
1877: if (last > ctx->text.lastPos)
1878: last = ctx->text.lastPos;
1879: if (last > next && ctx->text.insertPos < next)
1880: last = next;
1881: DeleteOrKill(ctx, ctx->text.insertPos, last, TRUE);
1882: EndAction(ctx);
1883: }
1884:
1885: static KillToEndOfParagraph(ctx, event)
1886: TextWidget ctx;
1887: XEvent *event;
1888: {
1889: XtTextPosition next;
1890:
1891: StartAction(ctx, event);
1892: next = ctx->text.source->scan(ctx->text.source, ctx->text.insertPos, XtstEOL, XtsdRight,
1893: 1, FALSE);
1894: if (next == ctx->text.insertPos)
1895: next = ctx->text.source->scan(ctx->text.source, next, XtstEOL, XtsdRight, 1, TRUE);
1896: DeleteOrKill(ctx, ctx->text.insertPos, next, TRUE);
1897: EndAction(ctx);
1898: }
1899:
1900: static int InsertNewLineAndBackup(ctx, event)
1901: TextWidget ctx;
1902: XEvent *event;
1903: {
1904: StartAction(ctx, event);
1905: InsertNewLineAndBackupInternal(ctx);
1906: EndAction(ctx);
1907: }
1908:
1909: static int InsertNewLineAndBackupInternal(ctx)
1910: TextWidget ctx;
1911: {
1912: XtTextBlock text;
1913: text.length = 1;
1914: text.ptr = "\n";
1915: text.firstPos = 0;
1916: if (ReplaceText(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) {
1917: XBell( XtDisplay(ctx), 50);
1918: return(EDITERROR);
1919: }
1920: _XtTextSetNewSelection(ctx, (XtTextPosition) 0, (XtTextPosition) 0);
1921: ctx->text.showposition = TRUE;
1922: return(EDITDONE);
1923: }
1924:
1925:
1926:
1927: static int InsertNewLine(ctx, event)
1928: TextWidget ctx;
1929: XEvent *event;
1930: {
1931: XtTextPosition next;
1932:
1933: StartAction(ctx, event);
1934: if (InsertNewLineAndBackupInternal(ctx))
1935: return(EDITERROR);
1936: next = ctx->text.source->scan(ctx->text.source, ctx->text.insertPos,
1937: XtstPositions, XtsdRight, 1, TRUE);
1938: ctx->text.insertPos = next;
1939: EndAction(ctx);
1940: return(EDITDONE);
1941: }
1942:
1943:
1944: static InsertNewLineAndIndent(ctx, event)
1945: TextWidget ctx;
1946: XEvent *event;
1947: {
1948: XtTextBlock text;
1949: XtTextPosition pos1, pos2;
1950:
1951: StartAction(ctx, event);
1952: pos1 = ctx->text.source->scan(ctx->text.source, ctx->text.insertPos,
1953: XtstEOL, XtsdLeft, 1, FALSE);
1954: pos2 = ctx->text.source->scan(ctx->text.source, pos1, XtstEOL,
1955: XtsdLeft, 1, TRUE);
1956: pos2 = ctx->text.source->scan(ctx->text.source, pos2, XtstWhiteSpace,
1957: XtsdRight, 1, TRUE);
1958: text.ptr = _XtTextGetText(ctx, pos1, pos2);
1959: text.length = strlen(text.ptr);
1960: if (InsertNewLine(ctx, event)) return;
1961: if (ReplaceText(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) {
1962: XBell(XtDisplay(ctx), 50);
1963: EndAction(ctx);
1964: return;
1965: }
1966: ctx->text.insertPos = ctx->text.source->scan(ctx->text.source,
1967: ctx->text.insertPos, XtstPositions, XtsdRight, text.length, TRUE);
1968: XtFree(text.ptr);
1969: EndAction(ctx);
1970: }
1971:
1972: static NewSelection(ctx, l, r)
1973: TextWidget ctx;
1974: XtTextPosition l, r;
1975: {
1976: char *ptr;
1977: _XtTextSetNewSelection(ctx, l, r);
1978: if (l < r) {
1979: ptr = _XtTextGetText(ctx, l, r);
1980: XStoreBuffer(XtDisplay(ctx), ptr, min(strlen(ptr), MAXCUT), 0);
1981: XtFree(ptr);
1982: }
1983: }
1984:
1985: static SelectWord(ctx, event)
1986: TextWidget ctx;
1987: XEvent *event;
1988: {
1989: XtTextPosition l, r;
1990: StartAction(ctx, event);
1991: l = ctx->text.source->scan(ctx->text.source, ctx->text.insertPos,
1992: XtstWhiteSpace, XtsdLeft, 1, FALSE);
1993: r = ctx->text.source->scan(ctx->text.source, l, XtstWhiteSpace,
1994: XtsdRight, 1, FALSE);
1995: NewSelection(ctx, l, r);
1996: EndAction(ctx);
1997: }
1998:
1999:
2000: static SelectAll(ctx, event)
2001: TextWidget ctx;
2002: XEvent *event;
2003: {
2004: StartAction(ctx, event);
2005: NewSelection(ctx, (XtTextPosition) 0, ctx->text.lastPos);
2006: EndAction(ctx);
2007: }
2008:
2009: static SelectStart(ctx, event)
2010: TextWidget ctx;
2011: XEvent *event;
2012: {
2013: StartAction(ctx, event);
2014: AlterSelection(ctx, XtsmTextSelect, XtactionStart);
2015: EndAction(ctx);
2016: }
2017:
2018: static SelectAdjust(ctx, event)
2019: TextWidget ctx;
2020: XEvent *event;
2021: {
2022: StartAction(ctx, event);
2023: AlterSelection(ctx, XtsmTextSelect, XtactionAdjust);
2024: EndAction(ctx);
2025: }
2026:
2027: static SelectEnd(ctx, event)
2028: TextWidget ctx;
2029: XEvent *event;
2030: {
2031: StartAction(ctx, event);
2032: AlterSelection(ctx, XtsmTextSelect, XtactionEnd);
2033: EndAction(ctx);
2034: }
2035:
2036: static ExtendStart(ctx, event)
2037: TextWidget ctx;
2038: XEvent *event;
2039: {
2040: StartAction(ctx, event);
2041: AlterSelection(ctx, XtsmTextExtend, XtactionStart);
2042: EndAction(ctx);
2043: }
2044:
2045: static ExtendAdjust(ctx, event)
2046: TextWidget ctx;
2047: XEvent *event;
2048: {
2049: StartAction(ctx, event);
2050: AlterSelection(ctx, XtsmTextExtend, XtactionAdjust);
2051: EndAction(ctx);
2052: }
2053:
2054: static ExtendEnd(ctx, event)
2055: TextWidget ctx;
2056: XEvent *event;
2057: {
2058: StartAction(ctx, event);
2059: AlterSelection(ctx, XtsmTextExtend, XtactionEnd);
2060: EndAction(ctx);
2061: }
2062:
2063:
2064: static RedrawDisplay(ctx, event)
2065: TextWidget ctx;
2066: XEvent *event;
2067: {
2068: StartAction(ctx, event);
2069: ForceBuildLineTable(ctx);
2070: DisplayTextWindow(ctx);
2071: EndAction(ctx);
2072: }
2073:
2074:
2075: _XtTextAbortDialog(ctx, event)
2076: TextWidget ctx;
2077: XEvent *event;
2078: {
2079: StartAction(ctx, event);
2080: if (ctx->text.dialog) {
2081: XtDestroyWidget(ctx->text.dialog);
2082: ctx->text.dialog = NULL;
2083: }
2084: EndAction(ctx);
2085: }
2086:
2087:
2088: /* Insert a file of the given name into the text. Returns 0 if file found,
2089: -1 if not. */
2090:
2091: static InsertFileNamed(ctx, str)
2092: TextWidget ctx;
2093: char *str;
2094: {
2095: int fid;
2096: XtTextBlock text;
2097: char buf[1000];
2098: XtTextPosition position;
2099:
2100: if (str == NULL || strlen(str) == 0) return -1;
2101: fid = open(str, O_RDONLY);
2102: if (fid <= 0) return -1;
2103: _XtTextPrepareToUpdate(ctx);
2104: position = ctx->text.insertPos;
2105: while ((text.length = read(fid, buf, 512)) > 0) {
2106: text.ptr = buf;
2107: (void) ReplaceText(ctx, position, position, &text);
2108: position = ctx->text.source->scan(ctx->text.source, position,
2109: XtstPositions, XtsdRight, text.length, TRUE);
2110: }
2111: (void) close(fid);
2112: ctx->text.insertPos = position;
2113: _XtTextExecuteUpdate(ctx);
2114: return 0;
2115: }
2116:
2117: static DoInsert(ctx)
2118: TextWidget ctx;
2119: {
2120: /* can't do dialog boxes yet
2121: if (InsertFileNamed(ctx, XtDialogGetValueString(XtDisplay(ctx), ctx->text.dialog)))
2122: XBell(XtDisplay(ctx), 50);
2123: else
2124: _XtTextAbortDialog(ctx);
2125: */
2126: }
2127:
2128: static TextFocusIn (ctx, event)
2129: TextWidget ctx;
2130: XEvent *event;
2131: { ctx->text.hasfocus = TRUE; }
2132:
2133: static void TextFocusOut(ctx, event)
2134: TextWidget ctx;
2135: XEvent *event;
2136: { ctx->text.hasfocus = FALSE; }
2137:
2138: #define STRBUFSIZE 100
2139:
2140: static XComposeStatus compose_status = {NULL, 0};
2141: static InsertChar(ctx, event)
2142: TextWidget ctx;
2143: XEvent *event;
2144: {
2145: char strbuf[STRBUFSIZE];
2146: int keycode;
2147: XtTextBlock text;
2148: text.length = XLookupString (event, strbuf, STRBUFSIZE,
2149: &keycode, &compose_status);
2150: if (text.length==0) return;
2151: StartAction(ctx, event);
2152: text.ptr = &strbuf[0];;
2153: text.firstPos = 0;
2154: if (ReplaceText(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) {
2155: XBell(XtDisplay(ctx), 50);
2156: EndAction(ctx);
2157: return;
2158: }
2159: ctx->text.insertPos =
2160: (*(ctx->text.source->scan))(ctx->text.source, ctx->text.insertPos,
2161: XtstPositions, XtsdRight, text.length, TRUE);
2162: _XtTextSetNewSelection(ctx, ctx->text.insertPos, ctx->text.insertPos);
2163:
2164: EndAction(ctx);
2165: }
2166:
2167: static InsertFile(ctx, event)
2168: TextWidget ctx;
2169: XEvent *event;
2170: {
2171: char *ptr;
2172: XtTextBlock text;
2173:
2174: /* this depends on dialog boxes...
2175:
2176: StartAction(ctx, event);
2177: if (ctx->text.source->editType(ctx->text.source) != XttextEdit) {
2178: XBell(XtDisplay(ctx), 50);
2179: EndAction(ctx);
2180: return;
2181: }
2182: if (ctx->text.s.left < ctx->text.s.right) {
2183: ptr = _XtTextGetText(ctx, ctx->text.s.left, ctx->text.s.right);
2184: DeleteCurrentSelection(ctx);
2185: if (InsertFileNamed(ctx, ptr)) {
2186: XBell( XtDisplay(ctx), 50);
2187: text.ptr = ptr;
2188: text.length = strlen(ptr);
2189: (void) ReplaceText(ctx, ctx->text.insertPos, ctx->text.insertPos, &text);
2190: ctx->text.s.left = ctx->text.insertPos;
2191: ctx->text.s.right = ctx->text.insertPos =
2192: ctx->text.source->scan(ctx->text.source, ctx->text.insertPos,
2193: XtstPositions, XtsdRight, text.length, TRUE);
2194: }
2195: XtFree(ptr);
2196: EndAction(ctx);
2197: return;
2198: }
2199: if (ctx->text.dialog)
2200: _XtTextAbortDialog(ctx);
2201: ctx->text.dialog = XtDialogCreate( XtDisplay(ctx), ctx->text.w, "Insert File:", "", (ArgList)NULL, 0);
2202: XtDialogAddButton( XtDisplay(ctx), ctx->text.dialog, "Abort", _XtTextAbortDialog, (caddr_t)ctx);
2203: XtDialogAddButton( XtDisplay(ctx), ctx->text.dialog, "DoIt", DoInsert, (caddr_t)ctx);
2204: XMapWindow( XtDisplay(ctx), ctx->text.dialog);
2205: EndAction(ctx);
2206: */
2207: }
2208:
2209: /* Actions Table */
2210:
2211: XtActionsRec textActionsTable [] = {
2212: /* motion bindings */
2213: {"forward-character", (caddr_t)MoveForwardChar},
2214: {"backward-character", (caddr_t)MoveBackwardChar},
2215: {"forward-word", (caddr_t)MoveForwardWord},
2216: {"backward-word", (caddr_t)MoveBackwardWord},
2217: {"forward-paragraph", (caddr_t)MoveForwardParagraph},
2218: {"backward-paragraph", (caddr_t)MoveBackwardParagraph},
2219: {"beginning-of-line", (caddr_t)MoveToLineStart},
2220: {"end-of-line", (caddr_t)MoveToLineEnd},
2221: {"next-line", (caddr_t)MoveNextLine},
2222: {"previous-line", (caddr_t)MovePreviousLine},
2223: {"next-page", (caddr_t)MoveNextPage},
2224: {"previous-page", (caddr_t)MovePreviousPage},
2225: {"beginning-of-file", (caddr_t)MoveBeginningOfFile},
2226: {"end-of-file", (caddr_t)MoveEndOfFile},
2227: {"scroll-one-line-up", (caddr_t)ScrollOneLineUp},
2228: {"scroll-one-line-down", (caddr_t)ScrollOneLineDown},
2229: /* delete bindings */
2230: {"delete-next-character", (caddr_t)DeleteForwardChar},
2231: {"delete-previous-character", (caddr_t)DeleteBackwardChar},
2232: {"delete-next-word", (caddr_t)DeleteForwardWord},
2233: {"delete-previous-word", (caddr_t)DeleteBackwardWord},
2234: {"delete-selection", (caddr_t)DeleteCurrentSelection},
2235: /* kill bindings */
2236: {"kill-word", (caddr_t)KillForwardWord},
2237: {"backward-kill-word", (caddr_t)KillBackwardWord},
2238: {"kill-selection", (caddr_t)KillCurrentSelection},
2239: {"kill-to-end-of-line", (caddr_t)KillToEndOfLine},
2240: {"kill-to-end-of-paragraph", (caddr_t)KillToEndOfParagraph},
2241: /* unkill bindings */
2242: {"unkill", (caddr_t)UnKill},
2243: {"stuff", (caddr_t)Stuff},
2244: /* new line stuff */
2245: {"newline-and-indent", (caddr_t)InsertNewLineAndIndent},
2246: {"newline-and-backup", (caddr_t)InsertNewLineAndBackup},
2247: {"newline", (caddr_t)InsertNewLine},
2248: /* Selection stuff */
2249: {"select-word", (caddr_t)SelectWord},
2250: {"select-all", (caddr_t)SelectAll},
2251: {"select-start", (caddr_t)SelectStart},
2252: {"select-adjust", (caddr_t)SelectAdjust},
2253: {"select-end", (caddr_t)SelectEnd},
2254: {"extend-start", (caddr_t)ExtendStart},
2255: {"extend-adjust", (caddr_t)ExtendAdjust},
2256: {"extend-end", (caddr_t)ExtendEnd},
2257: /* Miscellaneous */
2258: {"redraw-display", (caddr_t)RedrawDisplay},
2259: {"insert-file", (caddr_t)InsertFile},
2260: {"insert-char", (caddr_t)InsertChar},
2261: {"focus-in", (caddr_t)TextFocusIn},
2262: {"focus-out", (caddr_t)TextFocusOut},
2263: {NULL,NULL}
2264: };
2265:
2266: static char *defaultTextEventBindings[] = {
2267: /* motion bindings */
2268: "Ctrl<Key>F: forward-character()",
2269: "<Key>0xff53: forward-character()",
2270: "Ctrl<Key>B: backward-character()",
2271: "<Key>0xff51: backward-character()",
2272: "Meta<Key>F: forward-word()",
2273: "Meta<Key>B: backward-word()",
2274: "Meta<Key>]: forward-paragraph()",
2275: "Ctrl<Key>[: backward-paragraph()",
2276: "Ctrl<Key>A: beginning-of-line()",
2277: "Ctrl<Key>E: end-of-line()",
2278: "Ctrl<Key>N: next-line()",
2279: "<Key>0xff54: next-line()",
2280: "Ctrl<Key>P: previous-line()",
2281: "<Key>0xff52: previous-line()",
2282: "Ctrl<Key>V: next-page()",
2283: "Meta<Key>V: previous-page()",
2284: "Meta<Key>\\<: beginning-of-file()",
2285: "Meta<Key>\\>: end-of-file()",
2286: "Ctrl<Key>Z: scroll-one-line-up()",
2287: "Meta<Key>Z: scroll-one-line-down()",
2288: /* delete binding*/
2289: "Ctrl<Key>D: delete-next-character()",
2290: "Ctrl<Key>H: delete-previous-character()",
2291: "<Key>0xff7f: delete-previous-character()",
2292: "<Key>0xffff: delete-previous-character()",
2293: "<Key>0xff08: delete-previous-character()",
2294: "Meta<Key>D: delete-next-word()",
2295: "Meta<Key>H: delete-previous-word()",
2296: /* kill bindings */
2297: "Shift Meta<Key>D: kill-word()",
2298: "Shift Meta<Key>H: backward-kill-word()",
2299: "Ctrl<Key>W: kill-selection()",
2300: "Ctrl<Key>K: kill-to-end-of-line()",
2301: "Meta<Key>K: kill-to-end-of-paragraph()",
2302: /* unkill bindings */
2303: "Ctrl<Key>Y: unkill()",
2304: "Meta<Key>Y: stuff()",
2305: /* new line stuff */
2306: "Ctrl<Key>J: newline-and-indent()",
2307: "<Key>0xff0a: newline-and-indent()",
2308: "Ctrl<Key>O: newline-and-backup()",
2309: "Ctrl<Key>M: newline()",
2310: "<Key>0xff0d: newline()",
2311: /* Miscellaneous */
2312: "Ctrl<Key>L: redraw-display()",
2313: "Meta<Key>I: insert-file()",
2314: "<FocusIn>: focus-in()",
2315: "<FocusOut>: focus-out()",
2316: /* selection stuff */
2317: "<Btn1Down>: select-start()",
2318: "Button1<PtrMoved>: extend-adjust()",
2319: "<Btn1Up>: extend-end()",
2320: "<Btn2Down>: stuff()",
2321: "<Btn3Down>: extend-start()",
2322: "Button3<PtrMoved>: extend-adjust()",
2323: "<Btn3Up>: extend-end()",
2324: /* default character handling */
2325: "<Key>: insert-char()",
2326:
2327: NULL
2328: };
2329:
2330: /* grodyness needed because Xrm wants pointer to thing, not thing... */
2331: caddr_t defaultTextTranslations = (caddr_t)defaultTextEventBindings;
2332:
2333: TextClassRec textClassRec = {
2334: /* core fields */
2335: /* superclass */ (WidgetClass) &widgetClassRec,
2336: /* class_name */ "Text",
2337: /* widget_size */ sizeof(TextRec),
2338: /* class_initialize */ NULL,
2339: /* class_inited */ FALSE,
2340: /* initialize */ Initialize,
2341: /* realize */ Realize,
2342: /* actions */ textActionsTable,
2343: /* num_actions */ XtNumber(textActionsTable),
2344: /* resources */ resources,
2345: /* num_ resource */ XtNumber(resources),
2346: /* xrm_class */ NULLQUARK,
2347: /* compress_motion */ TRUE,
2348: /* compress_exposure */ FALSE,
2349: /* visible_interest */ FALSE,
2350: /* destroy */ TextDestroy,
2351: /* resize */ Resize,
2352: /* expose */ ProcessExposeRegion,
2353: /* set_values */ XtTextSetValues,
2354: /* accept_focus */ TextAcceptFocus,
2355: };
2356:
2357: WidgetClass textWidgetClass = (WidgetClass)&textClassRec;
2358:
2359:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.