1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #ifdef HAVE_CONFIG_H
30 #include "../config.h"
31 #endif
32
33 #include "textDisp.h"
34 #include "textBuf.h"
35 #include "text.h"
36 #include "textP.h"
37 #include "nedit.h"
38 #include "calltips.h"
39 #include "highlight.h"
40 #include "rangeset.h"
41 #include "../util/nedit_malloc.h"
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <limits.h>
47 #include <ctype.h>
48 #ifndef __MVS__
49 #include <sys/param.h>
50 #endif
51
52 #include <Xm/Xm.h>
53 #include <Xm/ScrolledW.h>
54 #include <Xm/ScrollBar.h>
55 #include <Xm/Label.h>
56 #include <X11/Shell.h>
57
58 #ifdef HAVE_DEBUG_H
59 #include "../debug.h"
60 #endif
61
62
63
64 #define FILL_SHIFT 8
65 #define SECONDARY_SHIFT 9
66 #define PRIMARY_SHIFT 10
67 #define HIGHLIGHT_SHIFT 11
68 #define STYLE_LOOKUP_SHIFT 0
69 #define BACKLIGHT_SHIFT 12
70
71 #define FILL_MASK (
1 <<
FILL_SHIFT)
72 #define SECONDARY_MASK (
1 <<
SECONDARY_SHIFT)
73 #define PRIMARY_MASK (
1 <<
PRIMARY_SHIFT)
74 #define HIGHLIGHT_MASK (
1 <<
HIGHLIGHT_SHIFT)
75 #define STYLE_LOOKUP_MASK (0xff <<
STYLE_LOOKUP_SHIFT)
76 #define BACKLIGHT_MASK (0xff <<
BACKLIGHT_SHIFT)
77
78 #define RANGESET_SHIFT (
20)
79 #define RANGESET_MASK (0x3F <<
RANGESET_SHIFT)
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 #define MAX_DISP_LINE_LEN 1000
101
102
103 #define TEXT_OF_TEXTD(t) (((TextWidget)((t)->w))->text)
104
105 #define MCURSOR_ALLOC 8
106 #define MCURSOR_MAX 1024
107 #define MCURSOR_ALLOC_RESET 32
108
109 enum positionTypes {
CURSOR_POS,
CHARACTER_POS};
110
111 static void updateLineStarts(textDisp *textD,
int pos,
int charsInserted,
112 int charsDeleted,
int linesInserted,
int linesDeleted,
int *scrolled);
113 static void offsetLineStarts(textDisp *textD,
int newTopLineNum);
114 static void calcLineStarts(textDisp *textD,
int startLine,
int endLine);
115 static void calcLastChar(textDisp *textD);
116 static int posToVisibleLineNum(textDisp *textD,
int pos,
int *lineNum);
117 static int getCharWidth(textDisp *textD,
const char *src_orig, FcChar32 *dst,
int len);
118 static FcChar32 getCharacter32(
const textDisp *textD,
const textBuffer* buf,
int pos,
int *charlen);
119 static void redisplayLine(textDisp *textD,
int visLineNum,
int leftClip,
120 int rightClip,
int leftCharIndex,
int rightCharIndex);
121 static void drawString(textDisp *textD,
int style,
int rbIndex,
int x,
int y,
int fromX,
122 int toX, FcChar32 *string,
int nChars, Boolean highlightLine, ansiStyle *ansi);
123 static void clearRect(textDisp *textD, XftColor *color,
int x,
int y,
124 int width,
int height);
125 static void drawCursor(textDisp *textD,
int x,
int y);
126 static int styleOfPos(textDisp *textD,
int lineStartPos,
127 int lineLen,
int lineIndex,
int dispIndex,
int thisChar);
128 static int charWidth4(
const textDisp* textD,
const FcChar32* string,
129 int length, NFont *font);
130 static NFont* styleFontList(
const textDisp* textD,
int style);
131 static int inSelection(selection *sel,
int pos,
int lineStartPos,
132 int dispIndex);
133 static int xyToPos(textDisp *textD,
int x,
int y,
int posType);
134 static void xyToUnconstrainedPos(textDisp *textD,
int x,
int y,
int *row,
135 int *column,
int posType);
136 static void bufPreDeleteCB(
int pos,
int nDeleted,
void *cbArg);
137 static void bufModifiedCB(
int pos,
int nInserted,
int nDeleted,
138 int nRestyled,
const char *deletedText,
void *cbArg);
139 static void setScroll(textDisp *textD,
int topLineNum,
int horizOffset,
140 int updateVScrollBar,
int updateHScrollBar);
141 static void hScrollCB(Widget w, XtPointer clientData, XtPointer callData);
142 static void vScrollCB(Widget w, XtPointer clientData, XtPointer callData);
143 static void visibilityEH(Widget w, XtPointer data, XEvent *event,
144 Boolean *continueDispatch);
145 static void redrawLineNumbers(textDisp *textD,
int top,
int height,
int clearAll);
146 static void updateVScrollBarRange(textDisp *textD);
147 static int updateHScrollBarRange(textDisp *textD);
148 static int max(
int i1,
int i2);
149 static int min(
int i1,
int i2);
150 static int countLines(
const char *string);
151 static int measureVisLine(textDisp *textD,
int visLineNum);
152 static int emptyLinesVisible(textDisp *textD);
153 static void blankSingleCursorProtrusions(textDisp *textD);
154 static void blankCursorProtrusions(textDisp *textD);
155 static void allocateFixedFontGCs(textDisp *textD, Pixel bgPixel, Pixel fgPixel);
156 static GC allocateGC(Widget w,
unsigned long valueMask,
157 unsigned long foreground,
unsigned long background, Font font,
158 unsigned long dynamicMask,
unsigned long dontCareMask);
159 static void releaseGC(Widget w,
GC gc);
160 static void resetClipRectangles(textDisp *textD);
161 static int visLineLength(textDisp *textD,
int visLineNum);
162 static void measureDeletedLines(textDisp *textD,
int pos,
int nDeleted);
163 static int findWrapRange(textDisp *textD,
const char *deletedText,
int pos,
164 int nInserted,
int nDeleted,
int *modRangeStart,
int *modRangeEnd,
165 int *linesInserted,
int *linesDeleted);
166 static void wrappedLineCounter(
const textDisp* textD,
const textBuffer* buf,
167 int startPos,
int maxPos,
int maxLines,
168 Boolean startPosIsLineStart,
int styleBufOffset,
169 int* retPos,
int* retLines,
int* retLineStart,
int* retLineEnd,
170 Boolean *retWrap);
171 static void findLineEnd(textDisp *textD,
int startPos,
int startPosIsLineStart,
172 int *lineEnd,
int *nextLineStart);
173 static int wrapUsesCharacter(textDisp *textD,
int lineEndPos);
174 static void hideOrShowHScrollBar(textDisp *textD);
175 static int rangeTouchesRectSel(selection *sel,
int rangeStart,
int rangeEnd);
176 static void extendRangeForStyleMods(textDisp *textD,
int *start,
int *end);
177 static int getAbsTopLineNum(textDisp *textD);
178 static void offsetAbsLineNum(textDisp *textD,
int oldFirstChar);
179 static int maintainingAbsTopLineNum(textDisp *textD);
180 static void resetAbsLineNum(textDisp *textD);
181 static int measurePropChar(
const textDisp* textD, FcChar32 c,
182 int colNum,
int pos);
183 static XftColor allocBGColor(Widget w,
char *colorName,
int *ok);
184 static XftColor* getRangesetColor(textDisp *textD,
int ind, XftColor *bground);
185 static void textDRedisplayRange(textDisp *textD,
int start,
int end);
186 static void findActiveAnsiStyle(textDisp *textD,
ssize_t pos, ansiStyle *style);
187 static int parseEscapeSequence(textBuffer *buf,
size_t pos, ansiStyle *style);
188 static void extendAnsiStyle(ansiStyle *style, ansiStyle *ext);
189 static void ansiFgToColorIndex(textDisp *textD,
short fg, XftColor *color);
190 static void ansiBgToColorIndex(textDisp *textD,
short bg, XftColor *color);
191
192 textDisp *TextDCreate(Widget widget, Widget hScrollBar, Widget vScrollBar,
193 Position left, Position top, Position width, Position height,
194 Position lineNumLeft, Position lineNumWidth, Position marginWidth,
195 textBuffer *buffer, NFont *font, NFont *bold, NFont *italic,
196 NFont *boldItalic, ColorProfile *colorProfile,
int continuousWrap,
197 int wrapMargin, XmString bgClassString, Pixel calltipFGPixel,
198 Pixel calltipBGPixel, Pixel lineHighlightBGPixel, Boolean indentRainbow,
199 Boolean highlightCursorLine, Boolean ansiColors)
200 {
201 textDisp *textD;
202 XGCValues gcValues;
203 int i;
204
205 XftFont *xftFont = FontDefault(font);
206
207 textD = (textDisp *)NEditMalloc(
sizeof(textDisp));
208 textD->w = widget;
209 textD->d =
NULL;
210 textD->top = top;
211 textD->left = left;
212 textD->width = width;
213 textD->height = height;
214 textD->marginWidth = marginWidth;
215 textD->cursorOn = True;
216
217
218
219
220
221
222
223
224 textD->cursorToHint =
NO_HINT;
225 textD->cursorStyle =
NORMAL_CURSOR;
226 textD->xic_x =
0;
227 textD->xic_y =
0;
228 textD->buffer = buffer;
229 textD->firstChar =
0;
230 textD->lastChar =
0;
231 textD->nBufferLines =
0;
232 textD->topLineNum =
1;
233 textD->absTopLineNum =
1;
234 textD->needAbsTopLineNum = False;
235 textD->horizOffset =
0;
236 textD->visibility = VisibilityUnobscured;
237 textD->hScrollBar = hScrollBar;
238 textD->vScrollBar = vScrollBar;
239 textD->font = FontRef(font);
240 textD->boldFont = FontRef(bold);
241 textD->italicFont = FontRef(italic);
242 textD->boldItalicFont = FontRef(boldItalic);
243 textD->ascent = xftFont->ascent;
244 textD->descent = xftFont->descent;
245 textD->fixedFontWidth = -
1;
246 textD->styleBuffer =
NULL;
247 textD->styleTable =
NULL;
248 textD->nStyles =
0;
249 textD->colorProfile = colorProfile;
250 textD->wrapMargin = wrapMargin;
251 textD->continuousWrap = continuousWrap;
252 allocateFixedFontGCs(
253 textD, colorProfile->textBgColor.pixel, colorProfile->textFgColor.pixel);
254 textD->lineNumLeft = lineNumLeft;
255 textD->lineNumWidth = lineNumWidth;
256 textD->nVisibleLines = (height -
1) / (textD->ascent + textD->descent) +
1;
257 gcValues.foreground = colorProfile->cursorFgColor.pixel;
258 textD->cursorFGGC = XtGetGC(widget, GCForeground, &gcValues);
259 textD->lineStarts = (
int *)NEditMalloc(
sizeof(
int) * textD->nVisibleLines);
260 textD->lineStarts[
0] =
0;
261 textD->calltipW =
NULL;
262 textD->calltipShell =
NULL;
263 textD->calltip.
ID =
0;
264 textD->calltipFGPixel = calltipFGPixel;
265 textD->calltipBGPixel = calltipBGPixel;
266 for (i=
1; i<textD->nVisibleLines; i++)
267 textD->lineStarts[i] = -
1;
268 textD->bgClassPixel =
NULL;
269 textD->bgClass =
NULL;
270 TextDSetupBGClasses(widget, bgClassString, &textD->bgClassPixel,
271 &textD->bgClass, colorProfile->textBgColor);
272 textD->suppressResync =
0;
273 textD->nLinesDeleted =
0;
274 textD->modifyingTabDist =
0;
275 textD->pointerHidden = False;
276 textD->disableRedisplay = False;
277 textD->fixLeftClipAfterResize = False;
278 textD->graphicsExposeQueue =
NULL;
279 textD->indentRainbow = indentRainbow;
280 textD->highlightCursorLine = highlightCursorLine;
281 textD->redrawCursorLine = False;
282
283
284
285 textD->mcursorAlloc =
MCURSOR_ALLOC;
286 textD->mcursorSize =
1;
287 textD->mcursorSizeReal =
1;
288 textD->multicursor = NEditCalloc(
MCURSOR_ALLOC,
sizeof(textCursor));
289 textD->mcursorOn =
FALSE;
290
291
292 textD->multicursor[
0].cursorPos =
0;
293 textD->multicursor[
0].cursorPosCache = -
1;
294 textD->multicursor[
0].cursorPosCacheLeft =
0;
295 textD->multicursor[
0].cursorPosCacheRight =
0;
296 textD->multicursor[
0].cursorPreferredCol = -
1;
297 textD->multicursor[
0].x = -
100;
298 textD->multicursor[
0].y = -
100;
299
300 textD->cursor = textD->multicursor;
301 textD->newcursor = textD->multicursor;
302
303 textD->cacheNoWrappingWidth =
0;
304 textD->cacheNoWrapping = False;
305
306 TextDSetAnsiColors(textD, ansiColors);
307
308
309
310 XtAddEventHandler(widget, VisibilityChangeMask, False,
311 visibilityEH, textD);
312
313
314
315 if (buffer !=
NULL) {
316 BufAddModifyCB(buffer, bufModifiedCB, textD);
317 BufAddPreDeleteCB(buffer, bufPreDeleteCB, textD);
318 }
319
320
321 if (vScrollBar !=
NULL) {
322 XtVaSetValues(vScrollBar, XmNminimum,
1, XmNmaximum,
2,
323 XmNsliderSize,
1, XmNrepeatDelay,
10, XmNvalue,
1,
NULL);
324 XtAddCallback(vScrollBar, XmNdragCallback, vScrollCB, (XtPointer)textD);
325 XtAddCallback(vScrollBar, XmNvalueChangedCallback, vScrollCB,
326 (XtPointer)textD);
327 }
328 if (hScrollBar !=
NULL) {
329 XtVaSetValues(hScrollBar, XmNminimum,
0, XmNmaximum,
1,
330 XmNsliderSize,
1, XmNrepeatDelay,
10, XmNvalue,
0,
331 XmNincrement, font->maxWidth,
NULL);
332 XtAddCallback(hScrollBar, XmNdragCallback, hScrollCB, (XtPointer)textD);
333 XtAddCallback(hScrollBar, XmNvalueChangedCallback, hScrollCB,
334 (XtPointer)textD);
335 }
336
337
338 if (buffer !=
NULL)
339 bufModifiedCB(
0, buffer->length,
0,
0,
NULL, textD);
340
341
342 hideOrShowHScrollBar(textD);
343
344 return textD;
345 }
346
347
348
349
350
351 void TextDInitXft(textDisp *textD) {
352 XWindowAttributes attributes;
353 XGetWindowAttributes(XtDisplay(textD->w), XtWindow(textD->w), &attributes);
354
355 Screen *screen = textD->w->core.screen;
356 Visual *visual = screen->root_visual;
357 for(
int i=
0;i<screen->ndepths;i++) {
358 Depth d = screen->depths[i];
359 if(d.depth == textD->w->core.depth) {
360 visual = d.visuals;
361 break;
362 }
363 }
364
365 Display *dp = XtDisplay(textD->w);
366 textD->d = XftDrawCreate(
367 dp,
368 XtWindow(textD->w),
369 visual,
370 textD->w->core.colormap);
371
372 }
373
374
375
376
377
378
379 void TextDFree(textDisp *textD)
380 {
381 FontUnref(textD->font);
382 FontUnref(textD->boldFont);
383 FontUnref(textD->italicFont);
384 FontUnref(textD->boldItalicFont);
385
386 NEditFree(textD->multicursor);
387
388 BufRemoveModifyCB(textD->buffer, bufModifiedCB, textD);
389 BufRemovePreDeleteCB(textD->buffer, bufPreDeleteCB, textD);
390 releaseGC(textD->w, textD->gc);
391 NEditFree(textD->lineStarts);
392 while (TextDPopGraphicExposeQueueEntry(textD)) {
393 }
394 NEditFree(textD->bgClassPixel);
395 NEditFree(textD->bgClass);
396 NEditFree(textD);
397 }
398
399
400
401
402 void TextDSetBuffer(textDisp *textD, textBuffer *buffer)
403 {
404
405
406 if (textD->buffer !=
NULL) {
407 bufModifiedCB(
0,
0, textD->buffer->length,
0,
NULL, textD);
408 BufRemoveModifyCB(textD->buffer, bufModifiedCB, textD);
409 BufRemovePreDeleteCB(textD->buffer, bufPreDeleteCB, textD);
410 }
411
412
413
414 textD->buffer = buffer;
415 BufAddModifyCB(buffer, bufModifiedCB, textD);
416 BufAddPreDeleteCB(buffer, bufPreDeleteCB, textD);
417
418
419 bufModifiedCB(
0, buffer->length,
0,
0,
NULL, textD);
420 }
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435 void TextDAttachHighlightData(textDisp *textD, textBuffer *styleBuffer,
436 styleTableEntry *styleTable,
int nStyles,
char unfinishedStyle,
437 unfinishedStyleCBProc unfinishedHighlightCB,
void *cbArg)
438 {
439 textD->styleBuffer = styleBuffer;
440 textD->styleTable = styleTable;
441 textD->nStyles = nStyles;
442 textD->unfinishedStyle = unfinishedStyle;
443 textD->unfinishedHighlightCB = unfinishedHighlightCB;
444 textD->highlightCBArg = cbArg;
445
446
447
448 TextDSetFont(textD, textD->font);
449 }
450
451
452 void TextDSetColorProfile(textDisp *textD, ColorProfile *profile)
453 {
454 XGCValues values;
455 Display *d = XtDisplay(textD->w);
456
457 textD->colorProfile = profile;
458
459 releaseGC(textD->w, textD->gc);
460 allocateFixedFontGCs(textD, profile->textBgColor.pixel, profile->textFgColor.pixel);
461
462
463 values.foreground = profile->cursorFgColor.pixel;
464 XChangeGC( d, textD->cursorFGGC, GCForeground, &values );
465
466
467 TextDRedisplayRect(textD, textD->left, textD->top, textD->width,
468 textD->height);
469 redrawLineNumbers(textD, textD->top, textD->height, True);
470 }
471
472
473
474
475 void TextDSetFont(textDisp *textD, NFont *font)
476 {
477 XftFont *fontStruct = FontDefault(font);
478 int i, maxAscent = fontStruct->ascent, maxDescent = fontStruct->descent;
479 int width, height;
480 XftFont *styleFont;
481 NFont *styleFontList;
482
483
484 if(!textD->disableRedisplay) {
485 blankCursorProtrusions(textD);
486 }
487
488
489
490 for (i=
0; i<textD->nStyles; i++) {
491 styleFontList = textD->styleTable[i].font;
492 styleFont = styleFontList ? FontDefault(styleFontList) :
NULL;
493 if (styleFont !=
NULL && styleFont->ascent > maxAscent)
494 maxAscent = styleFont->ascent;
495 if (styleFont !=
NULL && styleFont->descent > maxDescent)
496 maxDescent = styleFont->descent;
497 }
498 textD->ascent = maxAscent;
499 textD->descent = maxDescent;
500
501
502
503 textD->fixedFontWidth = -
1;
504
505
506 if (textD->height < maxAscent + maxDescent)
507 textD->height = maxAscent + maxDescent;
508
509 if(textD->font != font) {
510 FontUnref(textD->font);
511 textD->font = FontRef(font);
512 }
513
514 if(textD->disableRedisplay) {
515 return;
516 }
517
518
519 width = textD->width;
520 height = textD->height;
521 textD->width = textD->height =
0;
522 TextDResize(textD, width, height);
523
524
525
526
527 clearRect(textD, &textD->colorProfile->textBgColor, textD->left,
528 textD->top + textD->height - maxAscent - maxDescent,
529 textD->width, maxAscent + maxDescent);
530
531
532 TextDRedisplayRect(textD, textD->left, textD->top, textD->width,
533 textD->height);
534
535
536 redrawLineNumbers(textD, textD->top, textD->height, True);
537 }
538
539 void TextDSetBoldFont(textDisp *textD, NFont *boldFont)
540 {
541 if(textD->boldFont != boldFont) {
542 FontUnref(textD->boldFont);
543 textD->boldFont = FontRef(boldFont);
544 }
545 }
546
547 void TextDSetItalicFont(textDisp *textD, NFont *italicFont)
548 {
549 if(textD->italicFont != italicFont) {
550 FontUnref(textD->italicFont);
551 textD->italicFont = FontRef(italicFont);
552 }
553 }
554
555 void TextDSetBoldItalicFont(textDisp *textD, NFont *boldItalicFont)
556 {
557 if(textD->boldItalicFont != boldItalicFont) {
558 FontUnref(textD->boldItalicFont);
559 textD->boldItalicFont = FontRef(boldItalicFont);
560 }
561 }
562
563 int TextDMinFontWidth(textDisp *textD, Boolean considerStyles)
564 {
565 int fontWidth = textD->font->minWidth;
566 int i;
567
568 if (considerStyles) {
569 for (i =
0; i < textD->nStyles; ++i) {
570 int thisWidth = (textD->styleTable[i].font)->minWidth;
571 if (thisWidth < fontWidth) {
572 fontWidth = thisWidth;
573 }
574 }
575 }
576 return fontWidth;
577 }
578
579 int TextDMaxFontWidth(textDisp *textD, Boolean considerStyles)
580 {
581 int fontWidth = textD->font->maxWidth;
582 int i;
583
584 if (considerStyles) {
585 for (i =
0; i < textD->nStyles; ++i) {
586 int thisWidth = textD->styleTable[i].font->maxWidth;
587 if (thisWidth > fontWidth) {
588 fontWidth = thisWidth;
589 }
590 }
591 }
592 return fontWidth;
593 }
594
595
596
597
598 void TextDResize(textDisp *textD,
int width,
int height)
599 {
600 int oldVisibleLines = textD->nVisibleLines;
601 int canRedraw = XtWindow(textD->w) !=
0;
602 int newVisibleLines = height / (textD->ascent + textD->descent);
603 int redrawAll = False;
604 int oldWidth = textD->width;
605 int exactHeight = height - height % (textD->ascent + textD->descent);
606
607 if(width > oldWidth) {
608 textD->fixLeftClipAfterResize = True;
609 }
610
611 textD->width = width;
612 textD->height = height;
613
614 if(width < textD->cacheNoWrappingWidth) {
615 textD->cacheNoWrapping = False;
616 }
617
618
619
620
621 if (textD->continuousWrap && textD->wrapMargin==
0 && width!=oldWidth && !textD->cacheNoWrapping) {
622 Boolean wrap0 = False;
623 Boolean wrap1 = False;
624
625 int oldFirstChar = textD->firstChar;
626
627 textD->firstChar = TextDStartOfLine(textD, textD->firstChar);
628 int toplinenum = TextDCountLinesW(textD,
0, textD->firstChar, True, &wrap0);
629 int count = TextDCountLinesW(textD, textD->firstChar, textD->buffer->length, True, &wrap1);
630
631
632 textD->nBufferLines = toplinenum + count;
633
634 if(!(wrap0 || wrap1)) {
635 textD->cacheNoWrapping = True;
636 textD->cacheNoWrappingWidth = width;
637 }
638
639 textD->topLineNum = toplinenum+
1;
640 redrawAll = True;
641 offsetAbsLineNum(textD, oldFirstChar);
642 }
643
644
645
646
647 if (oldVisibleLines < newVisibleLines) {
648 NEditFree(textD->lineStarts);
649 textD->lineStarts = (
int *)NEditMalloc(
sizeof(
int) * newVisibleLines);
650 }
651 textD->nVisibleLines = newVisibleLines;
652 calcLineStarts(textD,
0, newVisibleLines);
653 calcLastChar(textD);
654
655
656
657 if (canRedraw && oldVisibleLines>newVisibleLines && exactHeight!=height)
658 XClearArea(XtDisplay(textD->w), XtWindow(textD->w), textD->left,
659 textD->top + exactHeight, textD->width,
660 height - exactHeight, False);
661
662
663
664 if (canRedraw && oldVisibleLines < newVisibleLines && textD->topLineNum +
665 textD->nVisibleLines > textD->nBufferLines)
666 setScroll(textD, max(
1, textD->nBufferLines - textD->nVisibleLines +
667 2 +
TEXT_OF_TEXTD(textD).cursorVPadding),
668 textD->horizOffset, False, False);
669
670
671
672
673 updateVScrollBarRange(textD);
674 if (updateHScrollBarRange(textD))
675 redrawAll = True;
676
677
678 if (redrawAll && canRedraw)
679 TextDRedisplayRect(textD, textD->left, textD->top, textD->width,
680 textD->height);
681
682
683 hideOrShowHScrollBar(textD);
684
685
686
687 redrawLineNumbers(textD, textD->top, textD->height, True);
688
689
690 TextDRedrawCalltip(textD,
0);
691 }
692
693
694
695
696
697 void TextDRedisplayRect(textDisp *textD,
int left,
int top,
int width,
698 int height)
699 {
700 int fontHeight, firstLine, lastLine, line;
701 if(textD->fixLeftClipAfterResize) {
702
703
704
705
706
707 int changeLeftClip = textD->font->fonts->font->max_advance_width;
708 if(left > changeLeftClip) {
709 left -= changeLeftClip;
710 width += changeLeftClip;
711 }
712 textD->fixLeftClipAfterResize = False;
713 }
714
715
716 fontHeight = textD->ascent + textD->descent;
717 firstLine = (top - textD->top - fontHeight +
1) / fontHeight;
718 lastLine = (top + height - textD->top) / fontHeight;
719
720
721
722 resetClipRectangles(textD);
723
724
725 for (line=firstLine; line<=lastLine; line++)
726 redisplayLine(textD, line, left-textD->marginWidth, left+width,
0,
INT_MAX);
727
728
729 if (textD->lineNumWidth !=
0 && left <= textD->lineNumLeft + textD->lineNumWidth) {
730 redrawLineNumbers(textD, top, height, True);
731 }
732 }
733
734
735
736
737
738
739
740
741 static void textDRedisplayRange(textDisp *textD,
int start,
int end)
742 {
743 int i, startLine, lastLine, startIndex, endIndex;
744
745
746 if (end < textD->firstChar || (start > textD->lastChar &&
747 !emptyLinesVisible(textD)))
748 return;
749
750
751 if (start <
0) start =
0;
752 if (start > textD->buffer->length) start = textD->buffer->length;
753 if (end <
0) end =
0;
754 if (end > textD->buffer->length) end = textD->buffer->length;
755
756
757 if (start < textD->firstChar) {
758 start = textD->firstChar;
759 }
760
761 if (!posToVisibleLineNum(textD, start, &startLine)) {
762 startLine = textD->nVisibleLines -
1;
763 }
764
765 if (end >= textD->lastChar) {
766 lastLine = textD->nVisibleLines -
1;
767 }
else {
768 if (!posToVisibleLineNum(textD, end, &lastLine)) {
769
770 lastLine = textD->nVisibleLines -
1;
771 }
772 }
773
774
775 startIndex = (textD->lineStarts[startLine] == -
1)
776 ?
0
777 : start - textD->lineStarts[startLine];
778 if (end >= textD->lastChar)
779 {
780
781
782 endIndex =
INT_MAX;
783 }
else if (textD->lineStarts[lastLine] == -
1)
784 {
785
786
787
788 endIndex =
0;
789 }
else
790 {
791 endIndex = end - textD->lineStarts[lastLine];
792 }
793
794
795
796 resetClipRectangles(textD);
797
798
799
800 if (startLine == lastLine) {
801 redisplayLine(textD, startLine,
0,
INT_MAX, startIndex, endIndex);
802 return;
803 }
804
805
806 redisplayLine(textD, startLine,
0,
INT_MAX, startIndex,
INT_MAX);
807
808
809 for (i=startLine+
1; i<lastLine; i++)
810 redisplayLine(textD, i,
0,
INT_MAX,
0,
INT_MAX);
811
812
813 redisplayLine(textD, lastLine,
0,
INT_MAX,
0, endIndex);
814 }
815
816
817
818
819
820 void TextDSetScroll(textDisp *textD,
int topLineNum,
int horizOffset)
821 {
822 int sliderSize, sliderMax;
823 int vPadding = (
int)(
TEXT_OF_TEXTD(textD).cursorVPadding);
824
825
826 if (topLineNum <
1)
827 topLineNum =
1;
828 else if ((topLineNum > textD->topLineNum) &&
829 (topLineNum > (textD->nBufferLines +
2 - textD->nVisibleLines +
830 vPadding)))
831 topLineNum = max(textD->topLineNum,
832 textD->nBufferLines +
2 - textD->nVisibleLines + vPadding);
833 XtVaGetValues(textD->hScrollBar, XmNmaximum, &sliderMax,
834 XmNsliderSize, &sliderSize,
NULL);
835 if (horizOffset <
0)
836 horizOffset =
0;
837 if (horizOffset > sliderMax - sliderSize)
838 horizOffset = sliderMax - sliderSize;
839
840 setScroll(textD, topLineNum, horizOffset, True, True);
841 }
842
843
844
845
846
847 void TextDGetScroll(textDisp *textD,
int *topLineNum,
int *horizOffset)
848 {
849 *topLineNum = textD->topLineNum;
850 *horizOffset = textD->horizOffset;
851 }
852
853
854
855
856 void TextDSetInsertPosition(textDisp *textD,
int newPos)
857 {
858 int oldLineStart, newLineStart, oldLineEnd, newLineEnd;
859 Boolean hiline = False;
860 if(textD->highlightCursorLine) {
861 oldLineStart = BufStartOfLine(textD->buffer, textD->cursor->cursorPos);
862 newLineStart = BufStartOfLine(textD->buffer, newPos);
863 if(oldLineStart != newLineStart || textD->mcursorOn || textD->redrawCursorLine) {
864 hiline = True;
865 oldLineEnd = BufEndOfLine(textD->buffer, textD->cursor->cursorPos);
866 newLineEnd = BufEndOfLine(textD->buffer, newPos);
867 textD->cursor->cursorPos = -
1;
868 }
869 }
870
871 Boolean redrawTextWidget =
0;
872 if(TextDClearMultiCursor(textD)) {
873 redrawTextWidget = True;
874 textD->cursor = textD->multicursor;
875 }
else if (newPos == textD->cursor->cursorPos) {
876
877 return;
878 }
879
880
881 if (newPos <
0) newPos =
0;
882 if (newPos > textD->buffer->length) newPos = textD->buffer->length;
883
884
885 textD->cursor->cursorPreferredCol = -
1;
886
887
888 TextDBlankCursor(textD);
889
890
891 textD->cursor->cursorPos = newPos;
892 textD->cursorOn = True;
893
894 if(redrawTextWidget) {
895
896 TextDRedisplayRect(textD,
0, textD->top, textD->width + textD->left, textD->height);
897 return;
898 }
899
900 int left, right;
901 TextDCursorLR(textD, &left, &right);
902 textDRedisplayRange(textD, left, right);
903
904 if(hiline) {
905 int oldLine = -
1, newLine = -
1, oldLine2 = -
1, newLine2 = -
1;
906
907 posToVisibleLineNum(textD, newLineStart, &newLine);
908 posToVisibleLineNum(textD, newLineEnd, &newLine2);
909
910 if(newLine == -
1 && newLine2 >=
0) {
911 newLine =
0;
912 }
913 if(newLine2 == -
1 && newLine >=
0) {
914 newLine2 = textD->nVisibleLines-
1;
915 }
916
917 posToVisibleLineNum(textD, oldLineStart, &oldLine);
918 posToVisibleLineNum(textD, oldLineEnd, &oldLine2);
919
920 if(oldLine == -
1 && oldLine2 >=
0) {
921 oldLine =
0;
922 }
923 if(oldLine2 == -
1 && oldLine >=
0) {
924 oldLine2 = textD->nVisibleLines-
1;
925 }
926
927 for(
int i=oldLine;i<=oldLine2;i++) {
928 redisplayLine(textD, i,
0,
INT_MAX,
0,
INT_MAX);
929 }
930
931 for(
int i=newLine;i<=newLine2;i++) {
932 redisplayLine(textD, i,
0,
INT_MAX,
0,
INT_MAX);
933 }
934 }
935 }
936
937
938
939
940 void TextDChangeCursors(textDisp *textD,
int startPos,
int diff) {
941
942 size_t newMCursorSize = textD->mcursorSize;
943 for(
int i=textD->mcursorSize-
1;i>=
0;i--) {
944 if(textD->multicursor[i].cursorPos < startPos) {
945 break;
946 }
947 textD->multicursor[i].cursorPos += diff;
948 textD->multicursor[i].cursorPreferredCol = -
1;
949
950
951 if(textD->multicursor[i].cursorPos > textD->buffer->length) {
952 newMCursorSize = i;
953 }
954 }
955 textD->mcursorSize = newMCursorSize >
0 ? newMCursorSize :
1;
956 textD->mcursorSizeReal = textD->mcursorSize;
957 if(textD->mcursorSize ==
1) {
958 textD->mcursorOn = False;
959 }
960 }
961
962 int TextDAddCursor(textDisp *textD,
int newMultiCursorPos) {
963 int mcInsertPos =
0;
964
965
966 for(
int i=
0;i<textD->mcursorSize;i++) {
967 if(textD->multicursor[i].cursorPos == newMultiCursorPos) {
968 return i;
969 }
else if(textD->multicursor[i].cursorPos > newMultiCursorPos) {
970 break;
971 }
972 mcInsertPos = i+
1;
973 }
974
975
976 if(textD->mcursorSize ==
MCURSOR_MAX) {
977 return -
1;
978 }
979
980
981 if(textD->mcursorSize == textD->mcursorAlloc) {
982 textD->mcursorAlloc *=
2;
983 textD->multicursor = NEditRealloc(textD->multicursor, textD->mcursorAlloc *
sizeof(textCursor));
984 }
985
986 textD->mcursorOn =
TRUE;
987
988
989 textD->mcursorSize++;
990 textD->mcursorSizeReal = textD->mcursorSize;
991 if(mcInsertPos+
1 < textD->mcursorSize) {
992
993
994 memmove(textD->multicursor+mcInsertPos+
1, textD->multicursor+mcInsertPos, (textD->mcursorSize-mcInsertPos-
1)*
sizeof(textCursor));
995 }
996 textCursor newCursor = TextDPos2Cursor(textD, newMultiCursorPos);
997 textD->multicursor[mcInsertPos] = newCursor;
998 textD->newcursor = &textD->multicursor[mcInsertPos];
999
1000 textD->cursor = textD->multicursor;
1001
1002
1003 textD->cursorOn = False;
1004 if(textD->highlightCursorLine) {
1005
1006
1007 int newCursorLine;
1008 posToVisibleLineNum(textD, newMultiCursorPos, &newCursorLine);
1009 redisplayLine(textD, newCursorLine,
0,
INT_MAX,
0,
INT_MAX);
1010 }
1011 TextDUnblankCursor(textD);
1012
1013 return -
1;
1014 }
1015
1016 void TextDRemoveCursor(textDisp *textD,
int cursorIndex) {
1017 if(textD->mcursorSize ==
1) {
1018 return;
1019 }
else if(textD->mcursorSize ==
2) {
1020 textD->mcursorOn =
FALSE;
1021 }
1022
1023 int cursorLine;
1024 posToVisibleLineNum(textD, textD->multicursor[cursorIndex].cursorPos, &cursorLine);
1025
1026 if(cursorIndex+
1 != textD->mcursorSize) {
1027 memmove(textD->multicursor + cursorIndex, textD->multicursor + cursorIndex +
1, (textD->mcursorSize - cursorIndex -
1)*
sizeof(textCursor));
1028 }
1029 textD->mcursorSize--;
1030 textD->mcursorSizeReal = textD->mcursorSize;
1031
1032 if(textD->highlightCursorLine) {
1033
1034 redisplayLine(textD, cursorLine,
0,
INT_MAX,
0,
INT_MAX);
1035 }
1036
1037 textD->newcursor = textD->cursor;
1038 }
1039
1040 void TextDSetCursors(textDisp *textD,
size_t *cursors,
size_t ncursors) {
1041 TextDBlankCursor(textD);
1042 textD->mcursorSize =
0;
1043 for(
int i=
0;i<ncursors;i++) {
1044 TextDAddCursor(textD, (
int)cursors[i]);
1045 }
1046 }
1047
1048 int TextDClearMultiCursor(textDisp *textD) {
1049 if(textD->mcursorSize >
1) {
1050 TextDBlankCursor(textD);
1051 textD->mcursorOn =
FALSE;
1052 textD->mcursorSize =
1;
1053 textD->mcursorSizeReal =
1;
1054 if(textD->mcursorAlloc >
MCURSOR_ALLOC_RESET) {
1055
1056 textD->mcursorAlloc =
MCURSOR_ALLOC;
1057 textD->multicursor = NEditRealloc(textD->multicursor,
MCURSOR_ALLOC *
sizeof(textCursor));
1058 }
1059 textD->cursor = textD->multicursor;
1060 textD->newcursor = textD->multicursor;
1061 return 1;
1062 }
1063 return 0;
1064 }
1065
1066 void TextDCheckCursorDuplicates(textDisp *textD) {
1067 size_t mcursorSize = textD->mcursorSize;
1068 for(
size_t i=
1;i<textD->mcursorSize;i++) {
1069 if(textD->multicursor[i].cursorPos == textD->multicursor[i-
1].cursorPos) {
1070 TextDRemoveCursor(textD, i);
1071 mcursorSize--;
1072 i--;
1073 }
1074 }
1075 textD->cursor = textD->multicursor;
1076 textD->newcursor = textD->multicursor;
1077
1078 if(textD->highlightCursorLine) {
1079 size_t lastPos = textD->multicursor[textD->mcursorSize-
1].cursorPos;
1080 int cursorLine;
1081 posToVisibleLineNum(textD, lastPos, &cursorLine);
1082
1083 if(cursorLine +
1 < textD->nVisibleLines) {
1084 redisplayLine(textD, cursorLine +
1,
0,
INT_MAX,
0,
INT_MAX);
1085 }
1086 }
1087 }
1088
1089 static void textDBlankCursorPos(textDisp *textD) {
1090 blankSingleCursorProtrusions(textD);
1091 textD->cursorOn = False;
1092 int left, right;
1093 TextDCursorLR(textD, &left, &right);
1094 textDRedisplayRange(textD, left, right);
1095 }
1096
1097 void TextDBlankCursor(textDisp *textD)
1098 {
1099 if (!textD->cursorOn)
1100 return;
1101
1102 if(textD->mcursorSize ==
1) {
1103 textDBlankCursorPos(textD);
1104 }
else {
1105 textCursor *origCursor = textD->cursor;
1106 for(
int i=
0;i<textD->mcursorSize;i++) {
1107 textD->cursor = textD->multicursor + i;
1108 textDBlankCursorPos(textD);
1109 }
1110 textD->cursor = origCursor;
1111 }
1112 }
1113
1114 void textDUnblankCursorPos(textDisp *textD) {
1115 int left, right;
1116 TextDCursorLR(textD, &left, &right);
1117 textDRedisplayRange(textD, left, right);
1118 }
1119
1120 void TextDUnblankCursor(textDisp *textD)
1121 {
1122 if (!textD->cursorOn) {
1123 textD->cursorOn = True;
1124 if(textD->mcursorSize ==
1) {
1125 textDUnblankCursorPos(textD);
1126 }
else {
1127 textCursor *origCursor = textD->cursor;
1128 for(
int i=
0;i<textD->mcursorSize;i++) {
1129 textD->cursor = textD->multicursor + i;
1130 textDUnblankCursorPos(textD);
1131 }
1132 textD->cursor = origCursor;
1133 }
1134 }
1135 }
1136
1137 void TextDSetCursorStyle(textDisp *textD,
int style)
1138 {
1139 textD->cursorStyle = style;
1140 blankCursorProtrusions(textD);
1141 if (textD->cursorOn) {
1142 int left, right;
1143 if(textD->mcursorSize ==
1) {
1144 TextDCursorLR(textD, &left, &right);
1145 textDRedisplayRange(textD, left, right);
1146 }
else {
1147 textCursor *origCursor = textD->cursor;
1148 for(
int i=
0;i<textD->mcursorSize;i++) {
1149 textD->cursor = textD->multicursor + i;
1150 TextDCursorLR(textD, &left, &right);
1151 textDRedisplayRange(textD, left, right);
1152 }
1153 textD->cursor = origCursor;
1154 }
1155 }
1156 }
1157
1158 Boolean TextDPosHasCursor(textDisp *textD,
int pos,
int *index) {
1159 *index = -
1;
1160 if(textD->mcursorSizeReal ==
1) {
1161 return pos == textD->cursor->cursorPos;
1162 }
else {
1163 for(
int i=
0;i<textD->mcursorSizeReal;i++) {
1164 int cursor = textD->multicursor[i].cursorPos;
1165 if(pos == cursor) {
1166 *index = i;
1167 return True;
1168 }
1169 }
1170 return False;
1171 }
1172 }
1173
1174 Boolean TextDRangeHasCursor(textDisp *textD,
int start,
int end) {
1175 if(textD->mcursorSizeReal ==
1) {
1176 int cursor = textD->cursor->cursorPos;
1177 return cursor >= start && cursor <= end;
1178 }
else {
1179 for(
int i=
0;i<textD->mcursorSizeReal;i++) {
1180 int cursor = textD->multicursor[i].cursorPos;
1181 if(cursor >= start && cursor <= end) {
1182 return True;
1183 }
1184 }
1185 return False;
1186 }
1187 }
1188
1189 void TextDSetWrapMode(textDisp *textD,
int wrap,
int wrapMargin)
1190 {
1191 textD->wrapMargin = wrapMargin;
1192 textD->continuousWrap = wrap;
1193 textD->cacheNoWrapping = False;
1194
1195
1196 Boolean retWrap;
1197 textD->nBufferLines = TextDCountLinesW(textD,
0, textD->buffer->length,
1198 True, &retWrap);
1199 if(!retWrap) {
1200 textD->cacheNoWrappingWidth = textD->width;
1201 textD->cacheNoWrapping = True;
1202 }
1203
1204
1205
1206
1207 textD->firstChar = TextDStartOfLine(textD, textD->firstChar);
1208 textD->topLineNum = TextDCountLines(textD,
0, textD->firstChar, True) +
1;
1209 resetAbsLineNum(textD);
1210
1211
1212 calcLineStarts(textD,
0, textD->nVisibleLines);
1213 calcLastChar(textD);
1214
1215
1216
1217 updateVScrollBarRange(textD);
1218 updateHScrollBarRange(textD);
1219
1220
1221 hideOrShowHScrollBar(textD);
1222
1223
1224 TextDRedisplayRect(textD,
0, textD->top, textD->width + textD->left,
1225 textD->height);
1226 }
1227
1228 int TextDGetInsertPosition(textDisp *textD)
1229 {
1230 return textD->cursor->cursorPos;
1231 }
1232
1233
1234
1235
1236
1237
1238
1239 void TextDInsert(textDisp *textD,
char *text)
1240 {
1241 int pos = textD->cursor->cursorPos;
1242
1243 textD->cursorToHint = pos + strlen(text);
1244 BufInsert(textD->buffer, pos, text);
1245 textD->cursorToHint =
NO_HINT;
1246 }
1247
1248
1249
1250
1251
1252 void TextDOverstrike(textDisp *textD,
char *text)
1253 {
1254 int startPos = textD->cursor->cursorPos;
1255 textBuffer *buf = textD->buffer;
1256 int lineStart = BufStartOfLine(buf, startPos);
1257 int textLen = strlen(text);
1258 int i, p, endPos, indent, startIndent, endIndent, inc;
1259 char *c, ch, *paddedText =
NULL;
1260
1261
1262 startIndent = BufCountDispChars(textD->buffer, lineStart, startPos);
1263 indent = startIndent;
1264 for (c=text; *c!=
'\0'; c+=inc) {
1265 inc = Utf8CharLen((
unsigned char*)c);
1266 if(inc >=
1) {
1267 indent++;
1268 }
else {
1269 indent += BufCharWidth(*c, indent, buf->tabDist, buf->nullSubsChar);
1270 }
1271 }
1272 endIndent = indent;
1273
1274
1275
1276 indent=startIndent;
1277 for (p=startPos; ; p+=inc) {
1278 if (p == buf->length)
1279 break;
1280 ch = BufGetCharacter(buf, p);
1281 inc = Utf8CharLen((
unsigned char*)&ch);
1282 if (ch ==
'\n')
1283 break;
1284 indent += BufCharWidth(ch, indent, buf->tabDist, buf->nullSubsChar);
1285 if (indent == endIndent) {
1286 p += inc;
1287 break;
1288 }
else if (indent > endIndent) {
1289 if (ch !=
'\t') {
1290 p += inc;
1291 paddedText = (
char*)NEditMalloc(textLen +
MAX_EXP_CHAR_LEN +
1);
1292 strcpy(paddedText, text);
1293 for (i=
0; i<indent-endIndent; i++)
1294 paddedText[textLen+i] =
' ';
1295 paddedText[textLen+i] =
'\0';
1296 }
1297 break;
1298 }
1299 }
1300 endPos = p;
1301
1302 textD->cursorToHint = startPos + textLen;
1303 BufReplace(buf, startPos, endPos, paddedText ==
NULL ? text : paddedText);
1304 textD->cursorToHint =
NO_HINT;
1305 NEditFree(paddedText);
1306 }
1307
1308
1309 XftColor PixelToColor(Widget w, Pixel p)
1310 {
1311 XColor xcolor;
1312 memset(&xcolor,
0,
sizeof(XColor));
1313 xcolor.pixel = p;
1314 XQueryColor(XtDisplay(w), w->core.colormap, &xcolor);
1315
1316 XftColor color;
1317 color.pixel = p;
1318 color.color.red = xcolor.red;
1319 color.color.green = xcolor.green;
1320 color.color.blue = xcolor.blue;
1321 color.color.alpha = 0xFFFF;
1322 return color;
1323 }
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340 int TextDXYToPosition(textDisp *textD,
int x,
int y)
1341 {
1342 return xyToPos(textD, x, y,
CURSOR_POS);
1343 }
1344
1345
1346
1347
1348 int TextDXYToCharPos(textDisp *textD,
int x,
int y)
1349 {
1350 return xyToPos(textD, x, y,
CHARACTER_POS);
1351 }
1352
1353
1354
1355
1356
1357
1358 void TextDXYToUnconstrainedPosition(textDisp *textD,
int x,
int y,
int *row,
1359 int *column)
1360 {
1361 xyToUnconstrainedPos(textD, x, y, row, column,
CURSOR_POS);
1362 }
1363
1364
1365
1366
1367
1368
1369 int TextDLineAndColToPos(textDisp *textD,
int lineNum,
int column)
1370 {
1371 int i, lineEnd, charIndex, outIndex, isMB;
1372 int lineStart=
0, charLen=
0;
1373 char expandedChar[
MAX_EXP_CHAR_LEN];
1374
1375
1376 if (lineNum <
1)
1377 lineNum =
1;
1378 lineEnd = -
1;
1379 for (i=
1; i<=lineNum && lineEnd<textD->buffer->length; i++) {
1380 lineStart = lineEnd +
1;
1381 lineEnd = BufEndOfLine(textD->buffer, lineStart);
1382 }
1383
1384
1385 if ( lineNum >= i ) {
1386 return lineEnd;
1387 }
1388
1389
1390 charIndex=
0;
1391
1392
1393 if (column >
0) {
1394
1395 char *lineStrAlloc;
1396 const char *lineStr = BufGetRange2(textD->buffer, lineStart, lineEnd, &lineStrAlloc);
1397 outIndex =
0;
1398 for(i=lineStart; i<lineEnd; i++, charIndex++) {
1399 charLen = BufExpandCharacter(lineStr+charIndex, lineEnd-charIndex,
1400 outIndex, expandedChar, textD->buffer->tabDist,
1401 textD->buffer->nullSubsChar, &isMB);
1402 if ( outIndex+charLen >= column )
break;
1403 outIndex+=charLen;
1404 }
1405 NEditFree(lineStrAlloc);
1406
1407
1408
1409
1410
1411 if (column >= outIndex + ( charLen /
2 ))
1412 charIndex++;
1413
1414
1415 if ((i>=lineEnd)&&(charIndex>
0)) charIndex--;
1416 }
1417
1418
1419 return lineStart + charIndex;
1420 }
1421
1422
1423
1424
1425
1426
1427
1428
1429 int TextDPositionToXY(textDisp *textD,
int pos,
int *x,
int *y)
1430 {
1431 int charIndex, lineStartPos, fontHeight, lineLen;
1432 int visLineNum, charLen, outIndex, xStep, charStyle, inc;
1433 FcChar32 expandedChar[
MAX_EXP_CHAR_LEN];
1434 FcChar32 uc;
1435 NFont *font;
1436
1437
1438 if (pos < textD->firstChar ||
1439 (pos > textD->lastChar && !emptyLinesVisible(textD)))
1440 return False;
1441
1442
1443 if (!posToVisibleLineNum(textD, pos, &visLineNum))
1444 return False;
1445 fontHeight = textD->ascent + textD->descent;
1446 *y = textD->top + visLineNum*fontHeight + fontHeight/
2;
1447
1448
1449
1450
1451 lineStartPos = textD->lineStarts[visLineNum];
1452 if (lineStartPos == -
1) {
1453 *x = textD->left - textD->horizOffset;
1454 return True;
1455 }
1456 lineLen = visLineLength(textD, visLineNum);
1457 char *lineStrAlloc;
1458 const char *lineStr = BufGetRange2(textD->buffer, lineStartPos, lineStartPos + lineLen, &lineStrAlloc);
1459
1460
1461
1462 xStep = textD->left - textD->horizOffset;
1463 outIndex =
0;
1464 for(charIndex=
0; charIndex<pos-lineStartPos; charIndex+=inc) {
1465 inc = getCharWidth(textD, lineStr+charIndex, &uc, lineLen - charIndex);
1466 if(inc >
1) {
1467 charLen =
1;
1468 expandedChar[
0] = uc;
1469 }
else {
1470 charLen = BufExpandCharacter4(lineStr[charIndex],
1471 outIndex,
1472 expandedChar,
1473 textD->buffer->tabDist, textD->buffer->nullSubsChar);
1474 }
1475
1476 charStyle = styleOfPos(textD, lineStartPos, lineLen, charIndex,
1477 outIndex, lineStr[charIndex]);
1478 font = styleFontList(textD, charStyle);
1479 xStep += charWidth4(textD, expandedChar, charLen, font);
1480 outIndex += charLen;
1481 }
1482 *x = xStep;
1483 NEditFree(lineStrAlloc);
1484 return True;
1485 }
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495 int TextDPosToLineAndCol(textDisp *textD,
int pos,
int *lineNum,
int *column)
1496 {
1497 textBuffer *buf = textD->buffer;
1498
1499
1500
1501
1502 if (textD->continuousWrap) {
1503 if (!maintainingAbsTopLineNum(textD) || pos < textD->firstChar ||
1504 pos > textD->lastChar)
1505 return False;
1506 *lineNum = textD->absTopLineNum + BufCountLines(buf,
1507 textD->firstChar, pos);
1508 *column = BufCountDispChars(buf, BufStartOfLine(buf, pos), pos);
1509 return True;
1510 }
1511
1512
1513 if (!posToVisibleLineNum(textD, pos, lineNum))
1514 return False;
1515 *column = BufCountDispChars(buf, textD->lineStarts[*lineNum], pos);
1516 *lineNum += textD->topLineNum;
1517 return True;
1518 }
1519
1520
1521
1522
1523 int TextDInSelection(textDisp *textD,
int x,
int y)
1524 {
1525 int row, column, pos = xyToPos(textD, x, y,
CHARACTER_POS);
1526 textBuffer *buf = textD->buffer;
1527
1528 xyToUnconstrainedPos(textD, x, y, &row, &column,
CHARACTER_POS);
1529 if (rangeTouchesRectSel(&buf->primary, textD->firstChar, textD->lastChar))
1530 column = TextDOffsetWrappedColumn(textD, row, column);
1531 return inSelection(&buf->primary, pos, BufStartOfLine(buf, pos), column);
1532 }
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544 int TextDOffsetWrappedColumn(textDisp *textD,
int row,
int column)
1545 {
1546 int lineStart, dispLineStart;
1547
1548 if (!textD->continuousWrap || row <
0 || row > textD->nVisibleLines)
1549 return column;
1550 dispLineStart = textD->lineStarts[row];
1551 if (dispLineStart == -
1)
1552 return column;
1553 lineStart = BufStartOfLine(textD->buffer, dispLineStart);
1554 return column + BufCountDispChars(textD->buffer, lineStart, dispLineStart);
1555 }
1556
1557
1558
1559
1560
1561
1562
1563
1564 int TextDOffsetWrappedRow(textDisp *textD,
int row)
1565 {
1566 if (!textD->continuousWrap || row <
0 || row > textD->nVisibleLines)
1567 return row;
1568 return BufCountLines(textD->buffer, textD->firstChar,
1569 textD->lineStarts[row]);
1570 }
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580 void TextDMakeInsertPosVisible(textDisp *textD)
1581 {
1582 int hOffset, topLine, x, y;
1583 int cursorPos = textD->cursor->cursorPos;
1584 int linesFromTop =
0, do_padding =
1;
1585 int cursorVPadding = (
int)
TEXT_OF_TEXTD(textD).cursorVPadding;
1586
1587 hOffset = textD->horizOffset;
1588 topLine = textD->topLineNum;
1589
1590
1591 do_padding = ((
TEXT_OF_TEXTD(textD).dragState ==
NOT_CLICKED) &&
1592 (cursorVPadding >
0));
1593
1594
1595 if (cursorPos < textD->firstChar) {
1596 topLine -= TextDCountLines(textD, cursorPos, textD->firstChar, False);
1597
1598 }
else if (cursorPos > textD->lastChar && !emptyLinesVisible(textD)) {
1599 topLine += TextDCountLines(textD, textD->lastChar -
1600 (wrapUsesCharacter(textD, textD->lastChar) ?
0 :
1),
1601 cursorPos, False);
1602 linesFromTop = textD->nVisibleLines-
1;
1603 }
else if (cursorPos == textD->lastChar && !emptyLinesVisible(textD) &&
1604 !wrapUsesCharacter(textD, textD->lastChar)) {
1605 topLine++;
1606 linesFromTop = textD->nVisibleLines-
1;
1607 }
else {
1608
1609 if (do_padding)
1610 linesFromTop = TextDCountLines(textD, textD->firstChar,
1611 cursorPos, True);
1612 }
1613 if (topLine <
1) {
1614 fprintf(stderr,
"xnedit: internal consistency check tl1 failed\n");
1615 topLine =
1;
1616 }
1617
1618 if (do_padding) {
1619
1620 if (textD->nVisibleLines <=
2*(
int)cursorVPadding) {
1621 topLine += (linesFromTop - textD->nVisibleLines/
2);
1622 topLine = max(topLine,
1);
1623 }
else if (linesFromTop < (
int)cursorVPadding) {
1624 topLine -= (cursorVPadding - linesFromTop);
1625 topLine = max(topLine,
1);
1626 }
else if (linesFromTop > textD->nVisibleLines-(
int)cursorVPadding-
1) {
1627 topLine += (linesFromTop - (textD->nVisibleLines-cursorVPadding-
1));
1628 }
1629 }
1630
1631
1632
1633
1634
1635 if (!TextDPositionToXY(textD, cursorPos, &x, &y)) {
1636 setScroll(textD, topLine, hOffset, True, True);
1637 if (!TextDPositionToXY(textD, cursorPos, &x, &y))
1638 return;
1639 }
1640 if (x > textD->left + textD->width)
1641 hOffset += x - (textD->left + textD->width);
1642 else if (x < textD->left)
1643 hOffset += x - textD->left;
1644
1645
1646 setScroll(textD, topLine, hOffset, True, True);
1647 }
1648
1649
1650
1651
1652
1653
1654 int TextDPreferredColumn(textDisp *textD,
int *visLineNum,
int *lineStartPos)
1655 {
1656 int column;
1657
1658
1659
1660 if (posToVisibleLineNum(textD, textD->cursor->cursorPos, visLineNum)) {
1661 *lineStartPos = textD->lineStarts[*visLineNum];
1662 }
1663 else {
1664 *lineStartPos = TextDStartOfLine(textD, textD->cursor->cursorPos);
1665 *visLineNum = -
1;
1666 }
1667
1668
1669 column = (textD->cursor->cursorPreferredCol >=
0)
1670 ? textD->cursor->cursorPreferredCol
1671 : BufCountDispChars(textD->buffer, *lineStartPos, textD->cursor->cursorPos);
1672 return(column);
1673 }
1674
1675
1676
1677
1678
1679 int TextDPosOfPreferredCol(textDisp *textD,
int column,
int lineStartPos)
1680 {
1681 int newPos;
1682
1683 newPos = BufCountForwardDispChars(textD->buffer, lineStartPos, column);
1684 if (textD->continuousWrap) {
1685 newPos = min(newPos, TextDEndOfLine(textD, lineStartPos, True));
1686 }
1687 return(newPos);
1688 }
1689
1690
1691
1692
1693 int TextDMoveRight(textDisp *textD)
1694 {
1695 if (textD->cursor->cursorPos >= textD->buffer->length)
1696 return False;
1697
1698 TextDSetInsertPosition(
1699 textD,
1700 BufRightPos(textD->buffer, textD->cursor->cursorPos));
1701 return True;
1702 }
1703
1704 int TextDMoveLeft(textDisp *textD)
1705 {
1706 if (textD->cursor->cursorPos <=
0)
1707 return False;
1708
1709 TextDSetInsertPosition(textD, BufLeftPos(textD->buffer, textD->cursor->cursorPos));
1710 return True;
1711 }
1712
1713 int TextDMoveUp(textDisp *textD,
int absolute)
1714 {
1715 int lineStartPos, column, prevLineStartPos, newPos, visLineNum;
1716
1717
1718
1719 if (absolute) {
1720 lineStartPos = BufStartOfLine(textD->buffer, textD->cursor->cursorPos);
1721 visLineNum = -
1;
1722 }
else if (posToVisibleLineNum(textD, textD->cursor->cursorPos, &visLineNum))
1723 lineStartPos = textD->lineStarts[visLineNum];
1724 else {
1725 lineStartPos = TextDStartOfLine(textD, textD->cursor->cursorPos);
1726 visLineNum = -
1;
1727 }
1728 if (lineStartPos ==
0)
1729 return False;
1730
1731
1732 column = textD->cursor->cursorPreferredCol >=
0
1733 ? textD->cursor->cursorPreferredCol
1734 : BufCountDispChars(textD->buffer, lineStartPos, textD->cursor->cursorPos);
1735
1736
1737 if (absolute) {
1738 prevLineStartPos = BufCountBackwardNLines(textD->buffer, lineStartPos,
1);
1739 }
else if (visLineNum != -
1 && visLineNum !=
0) {
1740 prevLineStartPos = textD->lineStarts[visLineNum-
1];
1741 }
else {
1742 prevLineStartPos = TextDCountBackwardNLines(textD, lineStartPos,
1);
1743 }
1744
1745 newPos = BufCountForwardDispChars(textD->buffer, prevLineStartPos, column);
1746 if (textD->continuousWrap && !absolute)
1747 newPos = min(newPos, TextDEndOfLine(textD, prevLineStartPos, True));
1748
1749
1750 TextDSetInsertPosition(textD, newPos);
1751
1752
1753 textD->cursor->cursorPreferredCol = column;
1754
1755 return True;
1756 }
1757
1758 int TextDMoveDown(textDisp *textD,
int absolute)
1759 {
1760 int lineStartPos, column, nextLineStartPos, newPos, visLineNum;
1761
1762 if (textD->cursor->cursorPos == textD->buffer->length) {
1763 return False;
1764 }
1765
1766 if (absolute) {
1767 lineStartPos = BufStartOfLine(textD->buffer, textD->cursor->cursorPos);
1768 visLineNum = -
1;
1769 }
else if (posToVisibleLineNum(textD, textD->cursor->cursorPos, &visLineNum)) {
1770 lineStartPos = textD->lineStarts[visLineNum];
1771 }
else {
1772 lineStartPos = TextDStartOfLine(textD, textD->cursor->cursorPos);
1773 visLineNum = -
1;
1774 }
1775
1776 column = textD->cursor->cursorPreferredCol >=
0
1777 ? textD->cursor->cursorPreferredCol
1778 : BufCountDispChars(textD->buffer, lineStartPos, textD->cursor->cursorPos);
1779
1780 if (absolute)
1781 nextLineStartPos = BufCountForwardNLines(textD->buffer, lineStartPos,
1);
1782 else
1783 nextLineStartPos = TextDCountForwardNLines(textD, lineStartPos,
1, True);
1784
1785 newPos = BufCountForwardDispChars(textD->buffer, nextLineStartPos, column);
1786
1787 if (textD->continuousWrap && !absolute) {
1788 newPos = min(newPos, TextDEndOfLine(textD, nextLineStartPos, True));
1789 }
1790
1791 TextDSetInsertPosition(textD, newPos);
1792 textD->cursor->cursorPreferredCol = column;
1793
1794 return True;
1795 }
1796
1797 textCursor TextDPos2Cursor(textDisp *textD,
int pos) {
1798 textBuffer *buf = textD->buffer;
1799 textCursor c;
1800 c.cursorPos = pos;
1801 c.cursorPosCache = pos;
1802 c.cursorPosCacheLeft = BufLeftPos(buf, pos);
1803 c.cursorPosCacheRight = BufRightPos(buf, pos);
1804 c.cursorPreferredCol = -
1;
1805 c.x = -
100;
1806 c.y = -
100;
1807 if(textD->ansiColors) {
1808 while(BufGetCharacter(buf, c.cursorPosCacheLeft) ==
'\e') {
1809 c.cursorPosCacheLeft = BufLeftPos(buf, c.cursorPosCacheLeft);
1810 }
1811 while(BufGetCharacter(buf, pos) ==
'\e') {
1812 c.cursorPosCacheRight += BufCharLen(buf, c.cursorPosCacheRight);
1813 pos = c.cursorPosCacheRight;
1814 }
1815 c.cursorPosCacheRight += BufCharLen(buf, textD->cursor->cursorPosCacheRight);
1816 }
1817 return c;
1818 }
1819
1820 void TextDCursorLR(textDisp *textD,
int *left,
int *right)
1821 {
1822 if(textD->cursor->cursorPos != textD->cursor->cursorPosCache) {
1823 textCursor c = TextDPos2Cursor(textD, textD->cursor->cursorPos);
1824 textD->cursor->cursorPosCache = c.cursorPosCache;
1825 textD->cursor->cursorPosCacheLeft = c.cursorPosCacheLeft;
1826 textD->cursor->cursorPosCacheRight = c.cursorPosCacheRight;
1827 }
1828 *left = textD->cursor->cursorPosCacheLeft;
1829 *right = textD->cursor->cursorPosCacheRight;
1830
1831 }
1832
1833 void TextDSetAnsiColors(textDisp *textD, Boolean ansiColors)
1834 {
1835 textD->ansiColors = ansiColors;
1836 if(ansiColors) {
1837 BufEnableAnsiEsc(textD->buffer);
1838 textD->cursor->cursorPosCache = -
1;
1839 }
else {
1840 BufDisableAnsiEsc(textD->buffer);
1841 }
1842 }
1843
1844
1845
1846
1847
1848
1849
1850 int TextDCountLines(textDisp *textD,
int startPos,
int endPos,
1851 int startPosIsLineStart)
1852 {
1853 Boolean retWrap;
1854 int retLines = TextDCountLinesW(textD, startPos, endPos, startPosIsLineStart, &retWrap);
1855 if(retWrap) {
1856 textD->cacheNoWrapping = False;
1857 }
1858 return retLines;
1859 }
1860
1861 int TextDCountLinesW(textDisp *textD,
int startPos,
int endPos,
1862 int startPosIsLineStart, Boolean *retWrapped)
1863 {
1864 int retLines, retPos, retLineStart, retLineEnd;
1865
1866
1867 if (!textD->continuousWrap) {
1868 if(retWrapped) {
1869 *retWrapped =
0;
1870 }
1871 return BufCountLines(textD->buffer, startPos, endPos);
1872 }
1873
1874 wrappedLineCounter(textD, textD->buffer, startPos, endPos,
INT_MAX,
1875 startPosIsLineStart,
0, &retPos, &retLines, &retLineStart,
1876 &retLineEnd, retWrapped);
1877
1878 return retLines;
1879 }
1880
1881
1882
1883
1884
1885
1886
1887 int TextDCountForwardNLines(
const textDisp* textD,
int startPos,
1888 unsigned nLines, Boolean startPosIsLineStart)
1889 {
1890 int retLines, retPos, retLineStart, retLineEnd;
1891
1892
1893 if (!textD->continuousWrap)
1894 return BufCountForwardNLines(textD->buffer, startPos, nLines);
1895
1896
1897 if (nLines ==
0)
1898 return startPos;
1899
1900
1901 wrappedLineCounter(textD, textD->buffer, startPos, textD->buffer->length,
1902 nLines, startPosIsLineStart,
0, &retPos, &retLines, &retLineStart,
1903 &retLineEnd,
NULL);
1904 return retPos;
1905 }
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923 int TextDEndOfLine(
const textDisp* textD,
int pos,
1924 Boolean startPosIsLineStart)
1925 {
1926 int retLines, retPos, retLineStart, retLineEnd;
1927
1928
1929 if (!textD->continuousWrap)
1930 return BufEndOfLine(textD->buffer, pos);
1931
1932 if (pos == textD->buffer->length)
1933 return pos;
1934 wrappedLineCounter(textD, textD->buffer, pos, textD->buffer->length,
1,
1935 startPosIsLineStart,
0, &retPos, &retLines, &retLineStart,
1936 &retLineEnd,
NULL);
1937 return retLineEnd;
1938 }
1939
1940
1941
1942
1943
1944 int TextDStartOfLine(
const textDisp* textD,
int pos)
1945 {
1946 int retLines, retPos, retLineStart, retLineEnd;
1947
1948
1949 if (!textD->continuousWrap)
1950 return BufStartOfLine(textD->buffer, pos);
1951
1952 wrappedLineCounter(textD, textD->buffer, BufStartOfLine(textD->buffer, pos),
1953 pos,
INT_MAX, True,
0, &retPos, &retLines, &retLineStart,
1954 &retLineEnd,
NULL);
1955 return retLineStart;
1956 }
1957
1958
1959
1960
1961
1962 int TextDCountBackwardNLines(textDisp *textD,
int startPos,
int nLines)
1963 {
1964 textBuffer *buf = textD->buffer;
1965 int pos, lineStart, retLines, retPos, retLineStart, retLineEnd;
1966
1967
1968 if (!textD->continuousWrap)
1969 return BufCountBackwardNLines(textD->buffer, startPos, nLines);
1970
1971 pos = startPos;
1972 while (True) {
1973 lineStart = BufStartOfLine(buf, pos);
1974 wrappedLineCounter(textD, textD->buffer, lineStart, pos,
INT_MAX,
1975 True,
0, &retPos, &retLines, &retLineStart, &retLineEnd,
1976 NULL);
1977 if (retLines > nLines)
1978 return TextDCountForwardNLines(textD, lineStart, retLines-nLines,
1979 True);
1980 nLines -= retLines;
1981 pos = lineStart -
1;
1982 if (pos <
0)
1983 return 0;
1984 nLines -=
1;
1985 }
1986 }
1987
1988
1989
1990
1991
1992 static void bufPreDeleteCB(
int pos,
int nDeleted,
void *cbArg)
1993 {
1994 textDisp *textD = (textDisp *)cbArg;
1995 if (textD->continuousWrap &&
1996 (textD->fixedFontWidth == -
1 || textD->modifyingTabDist))
1997
1998
1999
2000
2001
2002
2003
2004
2005 measureDeletedLines(textD, pos, nDeleted);
2006 else
2007 textD->suppressResync =
0;
2008 }
2009
2010
2011
2012
2013 static void bufModifiedCB(
int pos,
int nInserted,
int nDeleted,
2014 int nRestyled,
const char *deletedText,
void *cbArg)
2015 {
2016 int linesInserted, linesDeleted, startDispPos, endDispPos;
2017 textDisp *textD = (textDisp *)cbArg;
2018 textBuffer *buf = textD->buffer;
2019 int oldFirstChar = textD->firstChar;
2020 int scrolled, origCursorPos = textD->cursor->cursorPos;
2021 int wrapModStart, wrapModEnd;
2022 int redrawLN = False;
2023
2024
2025 if (nInserted !=
0 || nDeleted !=
0)
2026 textD->cursor->cursorPreferredCol = -
1;
2027
2028
2029
2030 if (textD->continuousWrap) {
2031 redrawLN = findWrapRange(textD, deletedText, pos, nInserted, nDeleted,
2032 &wrapModStart, &wrapModEnd, &linesInserted, &linesDeleted);
2033 if(!redrawLN && nDeleted >
0) {
2034 for(
int i=
0;i<nDeleted;i++) {
2035 if(deletedText[i] ==
'\n') {
2036 redrawLN =
1;
2037 break;
2038 }
2039 }
2040 }
2041 }
else {
2042 linesInserted = nInserted ==
0 ?
0 :
2043 BufCountLines(buf, pos, pos + nInserted);
2044 linesDeleted = nDeleted ==
0 ?
0 : countLines(deletedText);
2045 }
2046
2047
2048 if (nInserted !=
0 || nDeleted !=
0) {
2049 if (textD->continuousWrap) {
2050 updateLineStarts(textD, wrapModStart, wrapModEnd-wrapModStart,
2051 nDeleted + pos-wrapModStart + (wrapModEnd-(pos+nInserted)),
2052 linesInserted, linesDeleted, &scrolled);
2053 }
else {
2054 updateLineStarts(textD, pos, nInserted, nDeleted, linesInserted,
2055 linesDeleted, &scrolled);
2056 }
2057 }
else
2058 scrolled = False;
2059
2060
2061
2062 if (maintainingAbsTopLineNum(textD) && (nInserted !=
0 || nDeleted !=
0)) {
2063 if (pos + nDeleted < oldFirstChar)
2064 textD->absTopLineNum += BufCountLines(buf, pos, pos + nInserted) -
2065 countLines(deletedText);
2066 else if (pos < oldFirstChar)
2067 resetAbsLineNum(textD);
2068 }
2069
2070
2071 textD->nBufferLines += linesInserted - linesDeleted;
2072
2073
2074
2075
2076
2077
2078
2079 updateVScrollBarRange(textD);
2080 scrolled |= updateHScrollBarRange(textD);
2081
2082
2083 if (textD->cursorToHint !=
NO_HINT) {
2084 textD->cursor->cursorPos = textD->cursorToHint;
2085 textD->cursorToHint =
NO_HINT;
2086 }
else if (textD->cursor->cursorPos > pos) {
2087 if(textD->mcursorSize >
1) {
2088
2089 TextDChangeCursors(textD, pos, nInserted - nDeleted);
2090 }
else {
2091 if (textD->cursor->cursorPos < pos + nDeleted)
2092 textD->cursor->cursorPos = pos;
2093 else
2094 textD->cursor->cursorPos += nInserted - nDeleted;
2095 }
2096 }
2097
2098
2099 Bool isLastCursor = textD->cursor == textD->multicursor + textD->mcursorSize -
1;
2100 if(scrolled && isLastCursor) {
2101 blankCursorProtrusions(textD);
2102 TextDRedisplayRect(textD,
0, textD->top, textD->width + textD->left,
2103 textD->height);
2104 if (textD->styleBuffer) {
2105 textD->styleBuffer->primary.selected = False;
2106 textD->styleBuffer->primary.zeroWidth = False;
2107 }
2108 return;
2109 }
2110
2111
2112
2113
2114
2115
2116 startDispPos = textD->continuousWrap ? wrapModStart : pos;
2117 int cpos = origCursorPos;
2118 if (textD->highlightCursorLine) {
2119 cpos = BufStartOfLine(buf, origCursorPos);
2120 }
2121 if (origCursorPos == startDispPos && textD->cursor->cursorPos != startDispPos) {
2122 startDispPos = min(startDispPos, BufLeftPos(buf, cpos));
2123 }
2124
2125 if (linesInserted == linesDeleted) {
2126 if (nInserted ==
0 && nDeleted ==
0)
2127 endDispPos = pos + nRestyled;
2128 else {
2129 endDispPos = textD->continuousWrap ? wrapModEnd :
2130 BufEndOfLine(buf, pos + nInserted) +
1;
2131 if (origCursorPos >= startDispPos &&
2132 (origCursorPos <= endDispPos || endDispPos == buf->length))
2133 blankCursorProtrusions(textD);
2134 }
2135
2136
2137
2138
2139
2140
2141
2142 if (linesInserted >
2 || redrawLN) redrawLineNumbers(textD, textD->top, textD->height, True);
2143 }
else {
2144 endDispPos = textD->lastChar +
1;
2145 if (origCursorPos >= pos) {
2146 blankCursorProtrusions(textD);
2147 }
2148
2149 redrawLineNumbers(textD, textD->top, textD->height, True);
2150 }
2151
2152
2153
2154
2155
2156 if (textD->styleBuffer)
2157 extendRangeForStyleMods(textD, &startDispPos, &endDispPos);
2158
2159
2160 textDRedisplayRange(textD, startDispPos, endDispPos);
2161 }
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173 void TextDMaintainAbsLineNum(textDisp *textD,
int state)
2174 {
2175 textD->needAbsTopLineNum = state;
2176 resetAbsLineNum(textD);
2177 }
2178
2179
2180
2181
2182
2183 static int getAbsTopLineNum(textDisp *textD)
2184 {
2185 if (!textD->continuousWrap)
2186 return textD->topLineNum;
2187 if (maintainingAbsTopLineNum(textD))
2188 return textD->absTopLineNum;
2189 return 0;
2190 }
2191
2192
2193
2194
2195 static void offsetAbsLineNum(textDisp *textD,
int oldFirstChar)
2196 {
2197 if (maintainingAbsTopLineNum(textD)) {
2198 if (textD->firstChar < oldFirstChar)
2199 textD->absTopLineNum -= BufCountLines(textD->buffer,
2200 textD->firstChar, oldFirstChar);
2201 else
2202 textD->absTopLineNum += BufCountLines(textD->buffer,
2203 oldFirstChar, textD->firstChar);
2204 }
2205 }
2206
2207
2208
2209
2210
2211 static int maintainingAbsTopLineNum(textDisp *textD)
2212 {
2213 return textD->continuousWrap &&
2214 (textD->lineNumWidth !=
0 || textD->needAbsTopLineNum);
2215 }
2216
2217
2218
2219
2220
2221
2222 static void resetAbsLineNum(textDisp *textD)
2223 {
2224 textD->absTopLineNum =
1;
2225 offsetAbsLineNum(textD,
0);
2226 }
2227
2228
2229
2230
2231
2232 static int posToVisibleLineNum(textDisp *textD,
int pos,
int *lineNum)
2233 {
2234 int i;
2235
2236 if (pos < textD->firstChar)
2237 return False;
2238 if (pos > textD->lastChar) {
2239 if (emptyLinesVisible(textD)) {
2240 if (textD->lastChar < textD->buffer->length) {
2241 if (!posToVisibleLineNum(textD, textD->lastChar, lineNum)) {
2242 fprintf(stderr,
"xnedit: Consistency check ptvl failed\n");
2243 return False;
2244 }
2245 return ++(*lineNum) <= textD->nVisibleLines-
1;
2246 }
else {
2247 posToVisibleLineNum(textD, max(textD->lastChar-
1,
0), lineNum);
2248 return True;
2249 }
2250 }
2251 return False;
2252 }
2253
2254 for (i=textD->nVisibleLines-
1; i>=
0; i--) {
2255 if (textD->lineStarts[i] != -
1 && pos >= textD->lineStarts[i]) {
2256 *lineNum = i;
2257 return True;
2258 }
2259 }
2260
2261 return False;
2262 }
2263
2264
2265
2266
2267
2268
2269 static int getCharWidth(textDisp *textD,
const char *src_orig, FcChar32 *dst,
int len)
2270 {
2271 if(textD->ansiColors && *src_orig ==
'\e') {
2272
2273 if(len <
3)
return 1;
2274 if(src_orig[
1] !=
'[')
return 1;
2275 int i;
2276 for(i=
2;i<len;i++) {
2277 char c = src_orig[i];
2278 if(c ==
'm') {
2279 i++;
2280 break;
2281 }
2282 if(c <
'0' || (c >
'9' && c !=
';'))
break;
2283 }
2284 *dst =
0;
2285 return i;
2286 }
else {
2287
2288 return Utf8ToUcs4(src_orig, dst, len);
2289 }
2290 }
2291
2292 static FcChar32 getCharacter32(
const textDisp *textD,
const textBuffer* buf,
int pos,
int *charlen)
2293 {
2294 if(textD->ansiColors) {
2295 if(BufGetCharacter(buf, pos) ==
'\e') {
2296 if(BufGetCharacter(buf, pos+
1) ==
'[') {
2297 int start = pos;
2298 pos +=
2;
2299 char c;
2300 while((c = BufGetCharacter(buf, pos)) !=
'\0') {
2301 if(c ==
'm') {
2302 pos++;
2303 break;
2304 }
2305 if(c <
'0' || (c >
'9' && c !=
';'))
break;
2306 pos++;
2307 }
2308 *charlen = pos - start;
2309 return 0;
2310 }
2311 }
2312 }
2313 return BufGetCharacter32(buf, pos, charlen);
2314 }
2315
2316 typedef struct _textCursorX {
2317 int cursorX;
2318 int index;
2319 } textCursorX;
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330 static void redisplayLine(textDisp *textD,
int visLineNum,
int leftClip,
2331 int rightClip,
int leftCharIndex,
int rightCharIndex)
2332 {
2333 textBuffer *buf = textD->buffer;
2334 int x, y, startX, charIndex, lineStartPos, lineLen, fontHeight, inc;
2335 int stdCharWidth, charWidth, startIndex, charStyle, style;
2336 int charLen, outStartIndex, outIndex, hasCursor = False;
2337 int dispIndexOffset, y_orig;
2338 int startOfLine =
INT_MAX;
2339 int endOfLine =
0;
2340 int cursorLine = False;
2341 FcChar32 expandedChar[
MAX_EXP_CHAR_LEN];
2342 FcChar32 outStr[
MAX_DISP_LINE_LEN];
2343 FcChar32 *outPtr;
2344 const char *lineStr;
2345 char *lineStrFree;
2346 char baseChar;
2347 FcChar32 uc =
0;
2348 NFont *styleFL = textD->font;
2349 NFont *charFL;
2350 XftFont *styleFont;
2351 XftFont *charFont;
2352 int rbTabDist =
TEXT_OF_TEXTD(textD).emulateTabs >
0 ?
2353 TEXT_OF_TEXTD(textD).emulateTabs : buf->tabDist;
2354 Boolean indentRainbow = textD->indentRainbow;
2355
2356 textCursorX singleCursor = { textD->cursor->cursorPos,
0 };
2357 textCursorX *cursorX = textD->mcursorSizeReal ==
1 ? &singleCursor : NEditCalloc(textD->mcursorSizeReal,
sizeof(textCursorX));
2358 int cursorNum =
0;
2359 int cursorIndex;
2360
2361
2362 if (visLineNum <
0 || visLineNum >= textD->nVisibleLines)
2363 return;
2364
2365
2366 leftClip = max(textD->left, leftClip);
2367 rightClip = min(rightClip, textD->left + textD->width);
2368
2369 if (leftClip > rightClip) {
2370 return;
2371 }
2372
2373
2374 fontHeight = textD->ascent + textD->descent;
2375 y = textD->top + visLineNum * fontHeight;
2376
2377
2378 lineStartPos = textD->lineStarts[visLineNum];
2379 if (lineStartPos == -
1) {
2380 lineLen =
0;
2381 lineStr =
NULL;
2382 lineStrFree =
NULL;
2383 }
else {
2384 lineLen = visLineLength(textD, visLineNum);
2385 lineStr = BufGetRange2(buf, lineStartPos, lineStartPos + lineLen, &lineStrFree);
2386 endOfLine = BufEndOfLine(buf, lineStartPos);
2387 if(textD->highlightCursorLine) {
2388 startOfLine = BufStartOfLine(buf, lineStartPos);
2389 }
2390 }
2391
2392
2393 int ansiS = -
1;
2394 int ansiCharS = -
1;
2395 ansiStyle newAnsiStyle = {-
1, -
1, -
1, -
1};
2396 ansiStyle ansi = {-
1, -
1, -
1, -
1};
2397 if(textD->ansiColors && lineStartPos >=
0) {
2398 findActiveAnsiStyle(textD, lineStartPos, &ansi);
2399 }
2400
2401
2402
2403
2404
2405
2406 stdCharWidth = textD->font->maxWidth;
2407 if (stdCharWidth <=
0) {
2408 fprintf(stderr,
"xnedit: Internal Error, bad font measurement\n");
2409 NEditFree(lineStrFree);
2410 return;
2411 }
2412
2413
2414
2415
2416
2417
2418 if (textD->continuousWrap && (rangeTouchesRectSel(&buf->primary,
2419 lineStartPos, lineStartPos + lineLen) || rangeTouchesRectSel(
2420 &buf->secondary, lineStartPos, lineStartPos + lineLen) ||
2421 rangeTouchesRectSel(&buf->highlight, lineStartPos,
2422 lineStartPos + lineLen))) {
2423 dispIndexOffset = BufCountDispChars(buf,
2424 BufStartOfLine(buf, lineStartPos), lineStartPos);
2425 }
else
2426 dispIndexOffset =
0;
2427
2428
2429
2430
2431
2432 x = textD->left - textD->horizOffset;
2433 outIndex =
0;
2434
2435 int rbEnd = lineLen;
2436 int rbCharIndex =
0;
2437 int rbPixelIndex =
0;
2438
2439 inc =
1;
2440 for (charIndex =
0; ; charIndex+=inc) {
2441 if(charIndex >= lineLen) {
2442 baseChar =
'\0';
2443 charLen =
1;
2444 inc =
1;
2445 }
else {
2446 baseChar = lineStr[charIndex];
2447 const char *line = lineStr + charIndex;
2448 int remainingLen = lineLen - charIndex;
2449
2450 inc = getCharWidth(textD, line, &uc, remainingLen);
2451 if(inc >
1) {
2452 charLen =
1;
2453 expandedChar[
0] = uc;
2454 }
else {
2455 charLen = BufExpandCharacter4(lineStr[charIndex],
2456 outIndex,
2457 expandedChar,
2458 buf->tabDist, buf->nullSubsChar);
2459 }
2460 }
2461
2462 style = styleOfPos(textD, lineStartPos, lineLen, charIndex,
2463 outIndex + dispIndexOffset, baseChar);
2464 charWidth = charIndex >= lineLen
2465 ? stdCharWidth
2466 : charWidth4(
2467 textD,
2468 expandedChar,
2469 charLen,
2470 styleFL = styleFontList(textD, style));
2471
2472 if (x + charWidth >= leftClip && charIndex >= leftCharIndex) {
2473 startIndex = charIndex;
2474 outStartIndex = outIndex;
2475 startX = x;
2476 styleFont = FindFont(styleFL, uc);
2477 break;
2478 }
2479
2480 if(textD->ansiColors && baseChar ==
'\e') {
2481 newAnsiStyle.fg = -
1;
2482 newAnsiStyle.bg = -
1;
2483 newAnsiStyle.bold = -
1;
2484 newAnsiStyle.italic = -
1;
2485 parseEscapeSequence(buf, lineStartPos + charIndex, &newAnsiStyle);
2486 extendAnsiStyle(&ansi, &newAnsiStyle);
2487 ansiS = charIndex;
2488 }
2489
2490 if(indentRainbow) {
2491 if(isspace(baseChar)) {
2492 if(baseChar ==
'\t') {
2493 rbCharIndex += buf->tabDist - rbCharIndex % buf->tabDist;
2494 }
else {
2495 rbCharIndex++;
2496 }
2497 }
else {
2498 rbEnd = charIndex;
2499 }
2500 }
2501
2502 x += charWidth;
2503 outIndex += charLen;
2504 }
2505
2506 rbPixelIndex = rbCharIndex / rbTabDist;
2507 if(rbEnd < startIndex) {
2508 indentRainbow =
0;
2509 }
2510
2511
2512
2513
2514
2515 if(textD->d) {
2516 XRectangle rect;
2517 rect.x =
0;
2518 rect.y =
0;
2519 rect.width = rightClip - leftClip;
2520 rect.height = textD->ascent + textD->descent;
2521 XftDrawSetClipRectangles(textD->d, leftClip, y, &rect,
1);
2522 }
2523
2524 int rbCurrentPixelIndex =
0;
2525 if(!indentRainbow) {
2526 rbCurrentPixelIndex = -
1;
2527 rbPixelIndex = -
1;
2528 }
2529
2530
2531
2532 if(textD->highlightCursorLine && TextDRangeHasCursor(textD, startOfLine, endOfLine)) {
2533 cursorLine = True;
2534 }
2535
2536
2537
2538
2539
2540 outPtr = outStr;
2541 outIndex = outStartIndex;
2542 x = startX;
2543 inc =
1;
2544 for (charIndex = startIndex; charIndex < rightCharIndex; charIndex += inc) {
2545 if (TextDPosHasCursor(textD, lineStartPos+charIndex, &cursorIndex)) {
2546 if (charIndex < lineLen
2547 || (charIndex == lineLen && (lineStartPos+charIndex) >= buf->length)) {
2548 hasCursor = True;
2549 cursorX[cursorNum].cursorX = x -
1;
2550 cursorX[cursorNum].index = cursorIndex;
2551 cursorNum++;
2552 }
else if (charIndex == lineLen) {
2553 if (wrapUsesCharacter(textD, (lineStartPos+charIndex))) {
2554 hasCursor = True;
2555 cursorX[cursorNum].cursorX = x -
1;
2556 cursorX[cursorNum].index = cursorIndex;
2557 cursorNum++;
2558 }
2559 }
2560 }
2561
2562 int cpCharLen;
2563 if(charIndex >= lineLen) {
2564 baseChar =
'\0';
2565 charLen =
1;
2566 rbCurrentPixelIndex = -
1;
2567 cpCharLen = -
1;
2568 }
else {
2569 baseChar = lineStr[charIndex];
2570
2571 if(indentRainbow) {
2572 if(isspace(baseChar)) {
2573 if(baseChar ==
'\t') {
2574 rbCharIndex += buf->tabDist - rbCharIndex % buf->tabDist;
2575 }
else {
2576 rbCharIndex++;
2577 }
2578 rbCurrentPixelIndex = ((rbCharIndex+rbTabDist-
1) / rbTabDist)+textD->colorProfile->numRainbowColors -
1;
2579 }
else {
2580 rbCurrentPixelIndex = -
1;
2581 indentRainbow =
0;
2582 if(rbCharIndex % rbTabDist >
0) {
2583
2584 rbPixelIndex = -
2;
2585 }
2586 }
2587 }
2588
2589 inc = getCharWidth(textD, lineStr+charIndex, &uc, lineLen - charIndex);
2590 if(inc >
1) {
2591 if(uc !=
0) {
2592 charLen =
1;
2593 expandedChar[
0] = uc;
2594 }
else {
2595 charLen =
0;
2596 }
2597 }
else {
2598 charLen = BufExpandCharacter4(lineStr[charIndex],
2599 outIndex,
2600 expandedChar,
2601 buf->tabDist, buf->nullSubsChar);
2602 }
2603 cpCharLen = charLen;
2604 }
2605
2606 if(textD->ansiColors && baseChar ==
'\e') {
2607 newAnsiStyle.fg = -
1;
2608 newAnsiStyle.bg = -
1;
2609 newAnsiStyle.bold = -
1;
2610 newAnsiStyle.italic = -
1;
2611 parseEscapeSequence(buf, lineStartPos + charIndex, &newAnsiStyle);
2612 ansiCharS = charIndex;
2613 }
2614
2615 charStyle = styleOfPos(textD, lineStartPos, lineLen, charIndex,
2616 outIndex + dispIndexOffset, baseChar);
2617 charFL = styleFontList(textD, charStyle);
2618 charFont = FindFont(charFL, uc);
2619
2620 if (charStyle != style || charFont != styleFont || rbPixelIndex != rbCurrentPixelIndex || ansiS != ansiCharS) {
2621 drawString(textD, style, rbPixelIndex, startX, y, max(startX, leftClip), min(x, rightClip), outStr, outPtr - outStr, cursorLine, &ansi);
2622 outPtr = outStr;
2623 startX = x;
2624 style = charStyle;
2625 styleFont = charFont;
2626 rbPixelIndex = rbCurrentPixelIndex;
2627 extendAnsiStyle(&ansi, &newAnsiStyle);
2628 }
2629 ansiS = ansiCharS;
2630
2631 if(cpCharLen ==
1) {
2632 *outPtr = *expandedChar;
2633 charWidth = charWidth4(textD, expandedChar, charLen, charFL);
2634 }
else if(charIndex < lineLen) {
2635 memcpy(outPtr, expandedChar,
sizeof(FcChar32)*charLen);
2636 charWidth = charWidth4(textD, expandedChar, charLen, charFL);
2637 }
else {
2638 charWidth = stdCharWidth;
2639 }
2640
2641 outPtr += charLen;
2642 x += charWidth;
2643 outIndex += charLen;
2644
2645 if (outPtr - outStr +
MAX_EXP_CHAR_LEN >=
MAX_DISP_LINE_LEN
2646 || x >= rightClip) {
2647 break;
2648 }
2649 }
2650 extendAnsiStyle(&ansi, &newAnsiStyle);
2651
2652
2653 drawString(textD, style, rbCurrentPixelIndex, startX, y, max(startX, leftClip), min(x, rightClip), outStr, outPtr - outStr, cursorLine, &ansi);
2654
2655
2656
2657
2658
2659 y_orig = textD->cursor->y;
2660 if (textD->cursorOn) {
2661 if (hasCursor) {
2662 for(
int i=
0;i<cursorNum;i++) {
2663 drawCursor(textD, cursorX[i].cursorX, y);
2664 cursorIndex = cursorX[i].index;
2665 if(cursorIndex >=
0) {
2666 textD->multicursor[cursorIndex].x = cursorX[i].cursorX;
2667 textD->multicursor[cursorIndex].y = y;
2668 }
2669 }
2670 }
else if (charIndex < lineLen
2671 && TextDPosHasCursor(textD, lineStartPos+charIndex+
1, &cursorIndex)
2672 && x == rightClip) {
2673 if ((lineStartPos+charIndex+
1) >= buf->length) {
2674 drawCursor(textD, x -
1, y);
2675 if(cursorIndex >=
0) {
2676 textD->multicursor[cursorIndex].x = x -
1;
2677 textD->multicursor[cursorIndex].y = y;
2678 }
2679 }
else {
2680 if (wrapUsesCharacter(textD, lineStartPos+charIndex+
1)) {
2681 drawCursor(textD, x -
1, y);
2682 if(cursorIndex >=
0) {
2683 textD->multicursor[cursorIndex].x = x -
1;
2684 textD->multicursor[cursorIndex].y = y;
2685 }
2686 }
2687 }
2688 }
else if (TextDPosHasCursor(textD, lineStartPos + rightCharIndex, &cursorIndex)) {
2689 drawCursor(textD, x -
1, y);
2690 if(cursorIndex >=
0) {
2691 textD->multicursor[cursorIndex].x = x -
1;
2692 textD->multicursor[cursorIndex].y = y;
2693 }
2694 }
2695 }
2696
2697
2698 if(hasCursor && textD->mcursorSizeReal ==
1) {
2699 int cx = cursorX[
0].cursorX;
2700
2701 if(cx != textD->xic_x || y != textD->xic_y) {
2702 TextWidget textwidget = (TextWidget)textD->w;
2703 if(textwidget->text.xic) {
2704
2705 XPoint ipos;
2706 ipos.x = cx - (FontDefault(textD->font)->max_advance_width /
3);
2707 ipos.y = y;
2708 XVaNestedList xicvals;
2709 xicvals = XVaCreateNestedList(
0, XNSpotLocation, &ipos,
NULL);
2710 XSetICValues(textwidget->text.xic, XNPreeditAttributes, xicvals,
NULL);
2711 XFree(xicvals);
2712 textD->xic_x = cx;
2713 textD->xic_y = y;
2714 }
2715 }
2716 }
2717
2718
2719 if (hasCursor && (y_orig != textD->cursor->y || y_orig != y))
2720 TextDRedrawCalltip(textD,
0);
2721
2722 NEditFree(lineStrFree);
2723 if(textD->mcursorSizeReal >
1) NEditFree(cursorX);
2724 }
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734 static void drawString(textDisp *textD,
int style,
int rbIndex,
int x,
int y,
int fromX,
2735 int toX, FcChar32 *string,
int nChars, Boolean highlightLine, ansiStyle *ansi)
2736 {
2737 if(toX < fromX || nChars ==
0)
return;
2738
2739 XftColor *gc = &textD->colorProfile->textFgColor;
2740 NFont *fontList = textD->font;
2741 XftColor *bground = &textD->colorProfile->textBgColor;
2742 XftColor *fground = &textD->colorProfile->textFgColor;
2743 int underlineStyle =
FALSE;
2744 XftColor color = textD->colorProfile->textFgColor;
2745
2746
2747 if (XtWindow(textD->w) ==
0)
2748 return;
2749
2750 if(nChars ==
0) rbIndex = -
1;
2751
2752
2753 if (rbIndex >=
0 || style & (
STYLE_LOOKUP_MASK |
BACKLIGHT_MASK |
RANGESET_MASK)) {
2754 gc = &textD->styleGC;
2755 }
2756 else if (style &
HIGHLIGHT_MASK) {
2757 bground = &textD->colorProfile->hiliteBgColor;
2758 color = textD->colorProfile->hiliteFgColor;
2759 }
2760 else if (style &
PRIMARY_MASK) {
2761 bground = &textD->colorProfile->selectBgColor;
2762 color = textD->colorProfile->selectFgColor;
2763 }
2764 else if (highlightLine && textD->highlightCursorLine) {
2765 bground = &textD->colorProfile->lineHiBgColor;
2766 }
2767 else {
2768 gc = &textD->colorProfile->textFgColor;
2769 }
2770
2771 if (gc == &textD->styleGC) {
2772
2773 styleTableEntry *styleRec;
2774
2775
2776
2777
2778 if (style &
STYLE_LOOKUP_MASK) {
2779 styleRec = &textD->styleTable[(style &
STYLE_LOOKUP_MASK) -
ASCII_A];
2780 underlineStyle = styleRec->underline;
2781 fontList = styleRec->font;
2782
2783 color = styleRec->color;
2784
2785 }
2786 else {
2787 styleRec =
NULL;
2788 fground = &textD->colorProfile->textFgColor;
2789 }
2790
2791
2792
2793
2794 bground =
2795 style &
PRIMARY_MASK ? &textD->colorProfile->selectBgColor :
2796 style &
HIGHLIGHT_MASK ? &textD->colorProfile->hiliteBgColor :
2797 style &
RANGESET_MASK ?
2798 getRangesetColor(textD,
2799 (style&
RANGESET_MASK)>>
RANGESET_SHIFT,
2800 bground) :
2801 rbIndex >=
0 ? &textD->colorProfile->rainbowColors[rbIndex%textD->colorProfile->numRainbowColors] :
2802 styleRec && styleRec->bgColorName ? &styleRec->bgColor :
2803 (style &
BACKLIGHT_MASK) && !(style &
FILL_MASK) ?
2804 &textD->bgClassPixel[(style>>
BACKLIGHT_SHIFT) & 0xff] :
2805 &textD->colorProfile->textBgColor;
2806 if (fground == bground)
2807 fground = &textD->colorProfile->textBgColor;
2808
2809
2810 if((bground == &textD->colorProfile->textBgColor || rbIndex >=
0) && highlightLine && textD->highlightCursorLine) {
2811 bground = &textD->colorProfile->lineHiBgColor;
2812 }
2813 }
2814
2815
2816 XftColor ansiBGColor;
2817 if(ansi->fg >
0) {
2818 ansiFgToColorIndex(textD, ansi->fg, &color);
2819 }
2820 if(ansi->bg >
0 && bground == &textD->colorProfile->textBgColor) {
2821 ansiBgToColorIndex(textD, ansi->bg, &ansiBGColor);
2822 bground = &ansiBGColor;
2823 }
2824 if(ansi->bold >
0 || ansi->italic >
0) {
2825 if(ansi->bold == ansi->italic) {
2826 fontList = textD->boldItalicFont;
2827 }
else if(ansi->bold ==
1) {
2828 fontList = textD->boldFont;
2829 }
else {
2830 fontList = textD->italicFont;
2831 }
2832 }
2833
2834
2835
2836
2837
2838
2839 if (toX >= textD->left) {
2840 clearRect(
2841 textD,
2842 bground,
2843 fromX,
2844 y,
2845 toX - fromX,
2846 textD->ascent + textD->descent);
2847 }
2848 if(style &
FILL_MASK) {
2849 return;
2850 }
2851
2852
2853
2854
2855
2856
2857
2858 XftFont *font = FindFont(fontList, string[
0]);
2859
2860
2861
2862
2863 if (font->ascent < textD->ascent)
2864 clearRect(textD, bground, fromX, y, toX - fromX, textD->ascent - font->ascent);
2865 if (font->descent < textD->descent)
2866 clearRect(textD, bground, fromX, y + textD->ascent + font->descent, toX - fromX,
2867 textD->descent - font->descent);
2868
2869
2870
2871
2872
2873 XftDrawString32(textD->d, &color, font, x, y + textD->ascent, string, nChars);
2874
2875
2876 if (style &
SECONDARY_MASK || underlineStyle)
2877 {
2878
2879
2880
2881 XftDrawRect(textD->d, fground, x, y + textD->ascent, toX -
1,
1);
2882 }
2883 }
2884
2885
2886
2887
2888 static void clearRect(textDisp *textD, XftColor *color,
int x,
int y,
2889 int width,
int height)
2890 {
2891
2892 if (width ==
0 || XtWindow(textD->w) ==
0)
2893 return;
2894
2895 if (color == &textD->colorProfile->textBgColor) {
2896 XClearArea(XtDisplay(textD->w), XtWindow(textD->w), x, y,
2897 width, height, False);
2898 }
2899 else {
2900 XftDrawRect(textD->d, color, x, y, width, height);
2901 }
2902 }
2903
2904
2905
2906
2907 static void drawCursor(textDisp *textD,
int x,
int y)
2908 {
2909 XSegment segs[
5];
2910 int left, right, cursorWidth, midY;
2911 int fontWidth = textD->font->minWidth;
2912 int fontHeight = textD->ascent + textD->descent;
2913 int nSegs =
0;
2914 int bot = y + fontHeight -
1;
2915
2916 if (XtWindow(textD->w) ==
0 || x < textD->left-
1 ||
2917 x > textD->left + textD->width)
2918 return;
2919
2920
2921
2922
2923 cursorWidth = (fontWidth/
3) *
2;
2924
2925
2926 if(textD->mcursorOn && textD->cursorStyle !=
CARET_CURSOR && textD->cursorStyle !=
BLOCK_CURSOR) {
2927 cursorWidth =
0;
2928 }
2929
2930 left = x - cursorWidth/
2;
2931 right = left + cursorWidth;
2932
2933
2934 if (textD->cursorStyle ==
CARET_CURSOR) {
2935 midY = bot - fontHeight/
5;
2936 segs[
0].x1 = left; segs[
0].y1 = bot; segs[
0].x2 = x; segs[
0].y2 = midY;
2937 segs[
1].x1 = x; segs[
1].y1 = midY; segs[
1].x2 = right; segs[
1].y2 = bot;
2938 segs[
2].x1 = left; segs[
2].y1 = bot; segs[
2].x2 = x; segs[
2].y2=midY-
1;
2939 segs[
3].x1 = x; segs[
3].y1=midY-
1; segs[
3].x2 = right; segs[
3].y2 = bot;
2940 nSegs =
4;
2941 }
else if (textD->cursorStyle ==
NORMAL_CURSOR) {
2942 segs[
0].x1 = left; segs[
0].y1 = y; segs[
0].x2 = right; segs[
0].y2 = y;
2943 segs[
1].x1 = x; segs[
1].y1 = y; segs[
1].x2 = x; segs[
1].y2 = bot;
2944 segs[
2].x1 = left; segs[
2].y1 = bot; segs[
2].x2 = right; segs[
2].y2=bot;
2945 nSegs =
3;
2946 }
else if (textD->cursorStyle ==
HEAVY_CURSOR) {
2947 segs[
0].x1 = x-
1; segs[
0].y1 = y; segs[
0].x2 = x-
1; segs[
0].y2 = bot;
2948 segs[
1].x1 = x; segs[
1].y1 = y; segs[
1].x2 = x; segs[
1].y2 = bot;
2949 segs[
2].x1 = x+
1; segs[
2].y1 = y; segs[
2].x2 = x+
1; segs[
2].y2 = bot;
2950 segs[
3].x1 = left; segs[
3].y1 = y; segs[
3].x2 = right; segs[
3].y2 = y;
2951 segs[
4].x1 = left; segs[
4].y1 = bot; segs[
4].x2 = right; segs[
4].y2=bot;
2952 nSegs =
5;
2953 }
else if (textD->cursorStyle ==
DIM_CURSOR) {
2954 midY = y + fontHeight/
2;
2955 segs[
0].x1 = x; segs[
0].y1 = y; segs[
0].x2 = x; segs[
0].y2 = y;
2956 segs[
1].x1 = x; segs[
1].y1 = midY; segs[
1].x2 = x; segs[
1].y2 = midY;
2957 segs[
2].x1 = x; segs[
2].y1 = bot; segs[
2].x2 = x; segs[
2].y2 = bot;
2958 nSegs =
3;
2959 }
else if (textD->cursorStyle ==
BLOCK_CURSOR) {
2960 right = x + fontWidth;
2961 segs[
0].x1 = x; segs[
0].y1 = y; segs[
0].x2 = right; segs[
0].y2 = y;
2962 segs[
1].x1 = right; segs[
1].y1 = y; segs[
1].x2 = right; segs[
1].y2=bot;
2963 segs[
2].x1 = right; segs[
2].y1 = bot; segs[
2].x2 = x; segs[
2].y2 = bot;
2964 segs[
3].x1 = x; segs[
3].y1 = bot; segs[
3].x2 = x; segs[
3].y2 = y;
2965 nSegs =
4;
2966 }
2967 XDrawSegments(XtDisplay(textD->w), XtWindow(textD->w),
2968 textD->cursorFGGC, segs, nSegs);
2969
2970
2971 textD->cursor->x = x;
2972 textD->cursor->y = y;
2973 }
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991 static int styleOfPos(textDisp *textD,
int lineStartPos,
2992 int lineLen,
int lineIndex,
int dispIndex,
int thisChar)
2993 {
2994 textBuffer *buf = textD->buffer;
2995 textBuffer *styleBuf = textD->styleBuffer;
2996 int pos, style =
0;
2997
2998 if (lineStartPos == -
1 || buf ==
NULL)
2999 return FILL_MASK;
3000
3001 pos = lineStartPos + min(lineIndex, lineLen);
3002
3003 if (lineIndex >= lineLen)
3004 style =
FILL_MASK;
3005 else if (styleBuf !=
NULL) {
3006 style = (
unsigned char)BufGetCharacter(styleBuf, pos);
3007 if (style == textD->unfinishedStyle) {
3008
3009 (textD->unfinishedHighlightCB)(textD, pos, textD->highlightCBArg);
3010 style = (
unsigned char)BufGetCharacter(styleBuf, pos);
3011 }
3012 }
3013 if (inSelection(&buf->primary, pos, lineStartPos, dispIndex))
3014 style |=
PRIMARY_MASK;
3015 if (inSelection(&buf->highlight, pos, lineStartPos, dispIndex))
3016 style |=
HIGHLIGHT_MASK;
3017 if (inSelection(&buf->secondary, pos, lineStartPos, dispIndex))
3018 style |=
SECONDARY_MASK;
3019
3020 if (buf->rangesetTable) {
3021 int rangesetIndex = RangesetIndex1ofPos(buf->rangesetTable, pos, True);
3022 style |= ((rangesetIndex <<
RANGESET_SHIFT) &
RANGESET_MASK);
3023 }
3024
3025
3026 if (textD->bgClass)
3027 {
3028 style |= (textD->bgClass[(
unsigned char)thisChar]<<
BACKLIGHT_SHIFT);
3029 }
3030 return style;
3031 }
3032
3033
3034
3035
3036
3037 static int charWidth4(
const textDisp* textD,
const FcChar32* string,
3038 int length, NFont *fontList)
3039 {
3040 if(string[
0] ==
0)
return 0;
3041
3042 int strWidth =
0;
3043 if(fontList->minWidth == fontList->maxWidth && string[
0] <
128) {
3044 strWidth += fontList->minWidth * length;
3045 }
else {
3046
3047 XftFont *font = FindFont(fontList, string[
0]);
3048 XGlyphInfo extents;
3049 XftTextExtents32(XtDisplay(textD->w), font, string, length, &extents);
3050 strWidth = extents.xOff;
3051 }
3052
3053 return strWidth;
3054 }
3055
3056 static NFont* styleFontList(
const textDisp* textD,
int style)
3057 {
3058 NFont *font;
3059 if (style &
STYLE_LOOKUP_MASK)
3060 font = textD->styleTable[(style &
STYLE_LOOKUP_MASK) -
ASCII_A].font;
3061 else
3062 font = textD->font;
3063 return font;
3064 }
3065
3066
3067
3068
3069
3070 static int inSelection(selection *sel,
int pos,
int lineStartPos,
int dispIndex)
3071 {
3072 return sel->selected &&
3073 ((!sel->rectangular &&
3074 pos >= sel->start && pos < sel->end) ||
3075 (sel->rectangular &&
3076 pos >= sel->start && lineStartPos <= sel->end &&
3077 dispIndex >= sel->rectStart && dispIndex < sel->rectEnd));
3078 }
3079
3080
3081
3082
3083
3084
3085
3086
3087 static int xyToPos(textDisp *textD,
int x,
int y,
int posType)
3088 {
3089 int charIndex, lineStart, lineLen, fontHeight;
3090 int charWidth, charLen, charStyle, visLineNum, xStep, outIndex, inc;
3091 FcChar32 expandedChar[
MAX_EXP_CHAR_LEN];
3092 FcChar32 uc =
0;
3093 NFont *font;
3094
3095
3096 fontHeight = textD->ascent + textD->descent;
3097 visLineNum = (y - textD->top) / fontHeight;
3098 if (visLineNum <
0)
3099 return textD->firstChar;
3100 if (visLineNum >= textD->nVisibleLines)
3101 visLineNum = textD->nVisibleLines -
1;
3102
3103
3104 lineStart = textD->lineStarts[visLineNum];
3105
3106
3107 if (lineStart == -
1)
3108 return textD->buffer->length;
3109
3110
3111 lineLen = visLineLength(textD, visLineNum);
3112 char *lineStrAlloc;
3113 const char *lineStr = BufGetRange2(textD->buffer, lineStart, lineStart + lineLen, &lineStrAlloc);
3114
3115
3116
3117 xStep = textD->left - textD->horizOffset;
3118 outIndex =
0;
3119 inc =
1;
3120 for(charIndex=
0; charIndex<lineLen; charIndex+=inc) {
3121 inc = getCharWidth(textD, lineStr+charIndex, &uc, lineLen-charIndex);
3122 if(inc >
1) {
3123
3124 charLen =
1;
3125 expandedChar[
0] = uc;
3126 }
else {
3127 charLen = BufExpandCharacter4(lineStr[charIndex],
3128 outIndex,
3129 expandedChar,
3130 textD->buffer->tabDist, textD->buffer->nullSubsChar);
3131 }
3132
3133 charStyle = styleOfPos(textD, lineStart, lineLen, charIndex, outIndex,
3134 lineStr[charIndex]);
3135 font = styleFontList(textD, charStyle);
3136 charWidth = charWidth4(textD, expandedChar, charLen, font);
3137 if (x < xStep + (posType ==
CURSOR_POS ? charWidth/
2 : charWidth)) {
3138 NEditFree(lineStrAlloc);
3139 return lineStart + charIndex;
3140 }
3141 xStep += charWidth;
3142 outIndex += charLen;
3143 }
3144
3145
3146
3147 NEditFree(lineStrAlloc);
3148 return lineStart + lineLen;
3149 }
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159 static void xyToUnconstrainedPos(textDisp *textD,
int x,
int y,
int *row,
3160 int *column,
int posType)
3161 {
3162 int fontHeight = textD->ascent + textD->descent;
3163 int fontWidth = textD->font->maxWidth;
3164
3165
3166 *row = (y - textD->top) / fontHeight;
3167 if (*row <
0) *row =
0;
3168 if (*row >= textD->nVisibleLines) *row = textD->nVisibleLines -
1;
3169 *column = ((x-textD->left) + textD->horizOffset +
3170 (posType ==
CURSOR_POS ? fontWidth/
2 :
0)) / fontWidth;
3171 if (*column <
0) *column =
0;
3172 }
3173
3174
3175
3176
3177
3178
3179
3180
3181 static void offsetLineStarts(textDisp *textD,
int newTopLineNum)
3182 {
3183 int oldTopLineNum = textD->topLineNum;
3184 int oldFirstChar = textD->firstChar;
3185 int lineDelta = newTopLineNum - oldTopLineNum;
3186 int nVisLines = textD->nVisibleLines;
3187 int *lineStarts = textD->lineStarts;
3188 int i, lastLineNum;
3189 textBuffer *buf = textD->buffer;
3190
3191
3192 if (lineDelta ==
0)
3193 return;
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205 lastLineNum = oldTopLineNum + nVisLines -
1;
3206 if (newTopLineNum < oldTopLineNum && newTopLineNum < -lineDelta) {
3207 textD->firstChar = TextDCountForwardNLines(textD,
0, newTopLineNum-
1,
3208 True);
3209
3210 }
else if (newTopLineNum < oldTopLineNum) {
3211 textD->firstChar = TextDCountBackwardNLines(textD, textD->firstChar,
3212 -lineDelta);
3213
3214 }
else if (newTopLineNum < lastLineNum) {
3215 textD->firstChar = lineStarts[newTopLineNum - oldTopLineNum];
3216
3217
3218 }
else if (newTopLineNum-lastLineNum < textD->nBufferLines-newTopLineNum) {
3219 textD->firstChar = TextDCountForwardNLines(textD,
3220 lineStarts[nVisLines-
1], newTopLineNum - lastLineNum, True);
3221
3222
3223 }
else {
3224 textD->firstChar = TextDCountBackwardNLines(textD, buf->length,
3225 textD->nBufferLines - newTopLineNum +
1);
3226
3227
3228 }
3229
3230
3231 if (lineDelta <
0 && -lineDelta < nVisLines) {
3232 for (i=nVisLines-
1; i >= -lineDelta; i--)
3233 lineStarts[i] = lineStarts[i+lineDelta];
3234 calcLineStarts(textD,
0, -lineDelta);
3235 }
else if (lineDelta >
0 && lineDelta < nVisLines) {
3236 for (i=
0; i<nVisLines-lineDelta; i++)
3237 lineStarts[i] = lineStarts[i+lineDelta];
3238 calcLineStarts(textD, nVisLines-lineDelta, nVisLines-
1);
3239 }
else
3240 calcLineStarts(textD,
0, nVisLines);
3241
3242
3243 calcLastChar(textD);
3244 textD->topLineNum = newTopLineNum;
3245
3246
3247
3248 offsetAbsLineNum(textD, oldFirstChar);
3249
3250
3251
3252
3253
3254
3255 }
3256
3257
3258
3259
3260
3261
3262
3263 static void updateLineStarts(textDisp *textD,
int pos,
int charsInserted,
3264 int charsDeleted,
int linesInserted,
int linesDeleted,
int *scrolled)
3265 {
3266 int *lineStarts = textD->lineStarts;
3267 int i, lineOfPos, lineOfEnd, nVisLines = textD->nVisibleLines;
3268 int charDelta = charsInserted - charsDeleted;
3269 int lineDelta = linesInserted - linesDeleted;
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281 if (pos + charsDeleted < textD->firstChar) {
3282 textD->topLineNum += lineDelta;
3283 for (i=
0; i<nVisLines && lineStarts[i] != -
1; i++)
3284 lineStarts[i] += charDelta;
3285
3286
3287
3288
3289
3290 textD->firstChar += charDelta;
3291 textD->lastChar += charDelta;
3292 *scrolled = False;
3293 return;
3294 }
3295
3296
3297
3298 if (pos < textD->firstChar) {
3299
3300 if (posToVisibleLineNum(textD, pos + charsDeleted, &lineOfEnd) &&
3301 ++lineOfEnd < nVisLines && lineStarts[lineOfEnd] != -
1) {
3302 textD->topLineNum = max(
1, textD->topLineNum + lineDelta);
3303 textD->firstChar = TextDCountBackwardNLines(textD,
3304 lineStarts[lineOfEnd] + charDelta, lineOfEnd);
3305
3306 }
else {
3307 if (textD->topLineNum > textD->nBufferLines + lineDelta) {
3308 textD->topLineNum =
1;
3309 textD->firstChar =
0;
3310 }
else
3311 textD->firstChar = TextDCountForwardNLines(textD,
0,
3312 textD->topLineNum -
1, True);
3313 }
3314 calcLineStarts(textD,
0, nVisLines-
1);
3315
3316
3317
3318
3319
3320
3321 calcLastChar(textD);
3322 *scrolled = True;
3323 return;
3324 }
3325
3326
3327
3328
3329
3330
3331 if (pos <= textD->lastChar) {
3332
3333 posToVisibleLineNum(textD, pos, &lineOfPos);
3334
3335 if (lineDelta ==
0) {
3336 for (i=lineOfPos+
1; i<nVisLines && lineStarts[i]!= -
1; i++)
3337 lineStarts[i] += charDelta;
3338 }
else if (lineDelta >
0) {
3339 for (i=nVisLines-
1; i>=lineOfPos+lineDelta+
1; i--)
3340 lineStarts[i] = lineStarts[i-lineDelta] +
3341 (lineStarts[i-lineDelta] == -
1 ?
0 : charDelta);
3342 }
else {
3343 for (i=max(
0,lineOfPos+
1); i<nVisLines+lineDelta; i++)
3344 lineStarts[i] = lineStarts[i-lineDelta] +
3345 (lineStarts[i-lineDelta] == -
1 ?
0 : charDelta);
3346 }
3347
3348
3349
3350
3351
3352
3353 if (linesInserted >=
0)
3354 calcLineStarts(textD, lineOfPos +
1, lineOfPos + linesInserted);
3355 if (lineDelta <
0)
3356 calcLineStarts(textD, nVisLines+lineDelta, nVisLines);
3357
3358
3359
3360
3361
3362
3363 calcLastChar(textD);
3364 *scrolled = False;
3365 return;
3366 }
3367
3368
3369
3370 if (emptyLinesVisible(textD)) {
3371 posToVisibleLineNum(textD, pos, &lineOfPos);
3372 calcLineStarts(textD, lineOfPos, lineOfPos+linesInserted);
3373 calcLastChar(textD);
3374
3375
3376
3377
3378
3379 *scrolled = False;
3380 return;
3381 }
3382
3383
3384 *scrolled = False;
3385 }
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395 static void calcLineStarts(textDisp *textD,
int startLine,
int endLine)
3396 {
3397 int startPos, bufLen = textD->buffer->length;
3398 int line, lineEnd, nextLineStart, nVis = textD->nVisibleLines;
3399 int *lineStarts = textD->lineStarts;
3400
3401
3402 if (nVis ==
0)
return;
3403 if (endLine <
0) endLine =
0;
3404 if (endLine >= nVis) endLine = nVis -
1;
3405 if (startLine <
0) startLine =
0;
3406 if (startLine >=nVis) startLine = nVis -
1;
3407 if (startLine > endLine)
3408 return;
3409
3410
3411 if (startLine ==
0) {
3412 lineStarts[
0] = textD->firstChar;
3413 startLine =
1;
3414 }
3415 startPos = lineStarts[startLine-
1];
3416
3417
3418
3419 if (startPos == -
1) {
3420 for (line=startLine; line<=endLine; line++)
3421 lineStarts[line] = -
1;
3422 return;
3423 }
3424
3425
3426
3427 for (line=startLine; line<=endLine; line++) {
3428 findLineEnd(textD, startPos, True, &lineEnd, &nextLineStart);
3429 startPos = nextLineStart;
3430 if (startPos >= bufLen) {
3431
3432
3433
3434
3435 if (line ==
0 || (lineStarts[line-
1] != bufLen &&
3436 lineEnd != nextLineStart)) {
3437 lineStarts[line] = bufLen;
3438 line++;
3439 }
3440 break;
3441 }
3442 lineStarts[line] = startPos;
3443 }
3444
3445
3446 for (; line<=endLine; line++)
3447 lineStarts[line] = -
1;
3448 }
3449
3450
3451
3452
3453
3454 static void calcLastChar(textDisp *textD)
3455 {
3456 int i;
3457
3458 for (i=textD->nVisibleLines-
1; i>
0 && textD->lineStarts[i]== -
1; i--);
3459 textD->lastChar = i <
0 ?
0 :
3460 TextDEndOfLine(textD, textD->lineStarts[i], True);
3461 }
3462
3463 void TextDImposeGraphicsExposeTranslation(textDisp *textD,
int *xOffset,
int *yOffset)
3464 {
3465 if (textD->graphicsExposeQueue) {
3466 graphicExposeTranslationEntry *thisGEQEntry = textD->graphicsExposeQueue->next;
3467 if (thisGEQEntry) {
3468 *xOffset += thisGEQEntry->horizontal;
3469 *yOffset += thisGEQEntry->vertical;
3470 }
3471 }
3472 }
3473
3474 Boolean TextDPopGraphicExposeQueueEntry(textDisp *textD)
3475 {
3476 graphicExposeTranslationEntry *removedGEQEntry = textD->graphicsExposeQueue;
3477
3478 if (removedGEQEntry) {
3479 textD->graphicsExposeQueue = removedGEQEntry->next;
3480 NEditFree(removedGEQEntry);
3481 }
3482 return(removedGEQEntry?True:False);
3483 }
3484
3485 void TextDTranlateGraphicExposeQueue(textDisp *textD,
int xOffset,
int yOffset, Boolean appendEntry)
3486 {
3487 graphicExposeTranslationEntry *newGEQEntry =
NULL;
3488 if (appendEntry) {
3489 newGEQEntry = (graphicExposeTranslationEntry *)NEditMalloc(
sizeof(graphicExposeTranslationEntry));
3490 newGEQEntry->next =
NULL;
3491 newGEQEntry->horizontal = xOffset;
3492 newGEQEntry->vertical = yOffset;
3493 }
3494 if (textD->graphicsExposeQueue) {
3495 graphicExposeTranslationEntry *iter = textD->graphicsExposeQueue;
3496 while (iter->next) {
3497 iter->next->horizontal += xOffset;
3498 iter->next->vertical += yOffset;
3499 iter = iter->next;
3500 }
3501 if (appendEntry) {
3502 iter->next = (
struct graphicExposeTranslationEntry *)newGEQEntry;
3503 }
3504 }
3505 else {
3506 if (appendEntry) {
3507 textD->graphicsExposeQueue = newGEQEntry;
3508 }
3509 }
3510 }
3511
3512 static void setScroll(textDisp *textD,
int topLineNum,
int horizOffset,
3513 int updateVScrollBar,
int updateHScrollBar)
3514 {
3515 int fontHeight = textD->ascent + textD->descent;
3516 int origHOffset = textD->horizOffset;
3517 int lineDelta = textD->topLineNum - topLineNum;
3518 int xOffset, yOffset, srcX, srcY, dstX, dstY, width, height;
3519 int exactHeight = textD->height - textD->height %
3520 (textD->ascent + textD->descent);
3521
3522
3523
3524 if (XtWindow(textD->w) ==
0 || (textD->horizOffset == horizOffset &&
3525 textD->topLineNum == topLineNum))
3526 return;
3527
3528
3529
3530 blankCursorProtrusions(textD);
3531
3532
3533
3534 offsetLineStarts(textD, topLineNum);
3535
3536
3537 textD->horizOffset = horizOffset;
3538
3539
3540
3541
3542 if (updateVScrollBar && textD->vScrollBar !=
NULL) {
3543 updateVScrollBarRange(textD);
3544 }
3545 if (updateHScrollBar && textD->hScrollBar !=
NULL) {
3546 updateHScrollBarRange(textD);
3547 }
3548
3549
3550
3551
3552 xOffset = origHOffset - textD->horizOffset;
3553 yOffset = lineDelta * fontHeight;
3554
3555
3556 if(
1) {
3557
3558
3559 TextDTranlateGraphicExposeQueue(textD, xOffset, yOffset, False);
3560 TextDRedisplayRect(textD, textD->left, textD->top, textD->width,
3561 textD->height);
3562 }
else {
3563
3564
3565
3566 srcX = textD->left + (xOffset >=
0 ?
0 : -xOffset);
3567 dstX = textD->left + (xOffset >=
0 ? xOffset :
0);
3568 width = textD->width - abs(xOffset);
3569 srcY = textD->top + (yOffset >=
0 ?
0 : -yOffset);
3570 dstY = textD->top + (yOffset >=
0 ? yOffset :
0);
3571 height = exactHeight - abs(yOffset);
3572 resetClipRectangles(textD);
3573 TextDTranlateGraphicExposeQueue(textD, xOffset, yOffset, True);
3574 XCopyArea(XtDisplay(textD->w), XtWindow(textD->w), XtWindow(textD->w),
3575 textD->gc, srcX, srcY, width, height, dstX, dstY);
3576
3577 if (yOffset >
0) {
3578 TextDRedisplayRect(textD, textD->left, textD->top,
3579 textD->width, yOffset);
3580 }
3581 else if (yOffset <
0) {
3582 TextDRedisplayRect(textD, textD->left, textD->top +
3583 textD->height + yOffset, textD->width, -yOffset);
3584 }
3585 if (xOffset >
0) {
3586 TextDRedisplayRect(textD, textD->left, textD->top,
3587 xOffset, textD->height);
3588 }
3589 else if (xOffset <
0) {
3590 TextDRedisplayRect(textD, textD->left + textD->width + xOffset,
3591 textD->top, -xOffset, textD->height);
3592 }
3593
3594 int left, right;
3595 TextDCursorLR(textD, &left, &right);
3596 textDRedisplayRange(textD, left, right);
3597 }
3598
3599
3600
3601 if (lineDelta !=
0) {
3602 redrawLineNumbers(textD, textD->top, textD->height, True);
3603 TextDRedrawCalltip(textD,
0);
3604 }
3605
3606 HandleAllPendingGraphicsExposeNoExposeEvents((TextWidget)textD->w,
NULL);
3607 }
3608
3609
3610
3611
3612
3613 static void updateVScrollBarRange(textDisp *textD)
3614 {
3615 int sliderSize, sliderMax, sliderValue;
3616
3617 if (textD->vScrollBar ==
NULL)
3618 return;
3619
3620
3621
3622
3623
3624 sliderSize = max(textD->nVisibleLines,
1);
3625 sliderValue = textD->topLineNum;
3626 sliderMax = max(textD->nBufferLines +
2 +
3627 TEXT_OF_TEXTD(textD).cursorVPadding,
3628 sliderSize + sliderValue);
3629 XtVaSetValues(textD->vScrollBar,
3630 XmNmaximum, sliderMax,
3631 XmNsliderSize, sliderSize,
3632 XmNpageIncrement, max(
1, textD->nVisibleLines -
1),
3633 XmNvalue, sliderValue,
NULL);
3634 }
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647 static int updateHScrollBarRange(textDisp *textD)
3648 {
3649 int i, maxWidth =
0, sliderMax, sliderWidth;
3650 int origHOffset = textD->horizOffset;
3651
3652 if (textD->hScrollBar ==
NULL || !XtIsManaged(textD->hScrollBar))
3653 return False;
3654
3655
3656 for (i=
0; i<textD->nVisibleLines && textD->lineStarts[i]!= -
1; i++)
3657 maxWidth = max(measureVisLine(textD, i), maxWidth);
3658
3659
3660
3661
3662 if (maxWidth < textD->width + textD->horizOffset && textD->horizOffset >
0)
3663 textD->horizOffset = max(
0, maxWidth - textD->width);
3664
3665
3666 sliderWidth = textD->width;
3667 sliderMax = max(maxWidth, sliderWidth + textD->horizOffset);
3668 XtVaSetValues(textD->hScrollBar,
3669 XmNmaximum, sliderMax,
3670 XmNsliderSize, sliderWidth,
3671 XmNpageIncrement, max(textD->width -
100,
10),
3672 XmNvalue, textD->horizOffset,
NULL);
3673
3674
3675 return origHOffset != textD->horizOffset;
3676 }
3677
3678
3679
3680
3681
3682 void TextDSetLineNumberArea(textDisp *textD,
int lineNumLeft,
int lineNumWidth,
3683 int textLeft)
3684 {
3685 int newWidth = textD->width + textD->left - textLeft;
3686 textD->lineNumLeft = lineNumLeft;
3687 textD->lineNumWidth = lineNumWidth;
3688 textD->left = textLeft;
3689 XClearWindow(XtDisplay(textD->w), XtWindow(textD->w));
3690 resetAbsLineNum(textD);
3691 TextDResize(textD, newWidth, textD->height);
3692 TextDRedisplayRect(textD,
0, textD->top,
INT_MAX, textD->height);
3693 }
3694
3695
3696
3697
3698
3699
3700
3701 static void redrawLineNumbers(textDisp *textD,
int top,
int height,
int clearAll)
3702 {
3703 int y, line, visLine, nCols, lineStart;
3704 char lineNumString[
12];
3705 int lineHeight = textD->ascent + textD->descent;
3706 int charWidth = textD->font->maxWidth;
3707 XRectangle clipRect;
3708
3709
3710
3711 if (textD->lineNumWidth ==
0 || XtWindow(textD->w) ==
0)
3712 return;
3713
3714
3715
3716
3717 clipRect.x =
0;
3718 clipRect.y =
0;
3719 clipRect.width = textD->lineNumWidth + textD->lineNumLeft;
3720 clipRect.height = textD->height +
2*textD->top;
3721
3722
3723 if(textD->d) {
3724 XftDrawSetClipRectangles(textD->d,
0,
0, &clipRect,
1);
3725 }
3726
3727
3728 if (clearAll) {
3729
3730
3731 XftDrawRect(
3732 textD->d,
3733 &textD->colorProfile->lineNoBgColor,
3734 0,
3735 0,
3736 textD->lineNumLeft + textD->lineNumWidth,
3737 2*top + height);
3738 }
3739
3740
3741 nCols = min(
11, textD->lineNumWidth / charWidth);
3742 y = textD->top;
3743 line = getAbsTopLineNum(textD);
3744 for (visLine=
0; visLine < textD->nVisibleLines; visLine++) {
3745 lineStart = textD->lineStarts[visLine];
3746 if (lineStart != -
1 && (lineStart==
0 ||
3747 BufGetCharacter(textD->buffer, lineStart-
1)==
'\n')) {
3748 snprintf(lineNumString,
12,
"%*d", nCols, line);
3749 XftDrawString8(
3750 textD->d,
3751 &textD->colorProfile->lineNoFgColor,
3752 FontDefault(textD->font),
3753 textD->lineNumLeft,
3754 y + textD->ascent,
3755 (FcChar8*)lineNumString,
3756 strlen(lineNumString));
3757 line++;
3758 }
else {
3759
3760
3761
3762
3763
3764 if (visLine ==
0)
3765 line++;
3766 }
3767 y += lineHeight;
3768 }
3769 }
3770
3771
3772
3773
3774 static void vScrollCB(Widget w, XtPointer clientData, XtPointer callData)
3775 {
3776 textDisp *textD = (textDisp *)clientData;
3777 int newValue = ((XmScrollBarCallbackStruct *)callData)->value;
3778 int lineDelta = newValue - textD->topLineNum;
3779
3780 if (lineDelta ==
0)
3781 return;
3782 setScroll(textD, newValue, textD->horizOffset, False, True);
3783 }
3784 static void hScrollCB(Widget w, XtPointer clientData, XtPointer callData)
3785 {
3786 textDisp *textD = (textDisp *)clientData;
3787 int newValue = ((XmScrollBarCallbackStruct *)callData)->value;
3788
3789 if (newValue == textD->horizOffset)
3790 return;
3791 setScroll(textD, textD->topLineNum, newValue, False, False);
3792 }
3793
3794 static void visibilityEH(Widget w, XtPointer data, XEvent *event,
3795 Boolean *continueDispatch)
3796 {
3797
3798
3799
3800 ((textDisp *)data)->visibility = ((XVisibilityEvent *)event)->state;
3801 }
3802
3803 static int max(
int i1,
int i2)
3804 {
3805 return i1 >= i2 ? i1 : i2;
3806 }
3807
3808 static int min(
int i1,
int i2)
3809 {
3810 return i1 <= i2 ? i1 : i2;
3811 }
3812
3813
3814
3815
3816 static int countLines(
const char *string)
3817 {
3818 const char *c;
3819 int lineCount =
0;
3820
3821 if (string ==
NULL)
3822 return 0;
3823 for (c=string; *c!=
'\0'; c++)
3824 if (*c ==
'\n') lineCount++;
3825 return lineCount;
3826 }
3827
3828
3829
3830
3831 static int measureVisLine(textDisp *textD,
int visLineNum)
3832 {
3833 textBuffer *buf = textD->buffer;
3834 int i, width =
0, style, lineLen = visLineLength(textD, visLineNum);
3835 int lineStartPos = textD->lineStarts[visLineNum];
3836 char *free_lineStr;
3837 const char *lineStr = BufGetRange2(buf, lineStartPos, lineStartPos + lineLen, &free_lineStr);
3838 FcChar32 expandedChar[
MAX_EXP_CHAR_LEN];
3839 FcChar32 uc;
3840 int inc;
3841 int charLen;
3842 unsigned short indent =
0;
3843 NFont *font;
3844
3845 for(i=
0;i<lineLen;i+=inc) {
3846 inc = getCharWidth(textD, lineStr+i, &uc, lineLen - i);
3847 if(inc >
1) {
3848 charLen =
1;
3849 expandedChar[
0] = uc;
3850 indent += inc;
3851 }
else {
3852 charLen = BufExpandCharacter4(lineStr[i],
3853 indent,
3854 expandedChar,
3855 buf->tabDist, buf->nullSubsChar);
3856 indent += charLen;
3857 }
3858
3859 if (textD->styleBuffer) {
3860 style = (
unsigned char)BufGetCharacter(textD->styleBuffer,
3861 lineStartPos+i) -
ASCII_A;
3862 font = textD->styleTable[style].font;
3863 }
else {
3864 font = textD->font;
3865 }
3866
3867 width += charWidth4(textD, expandedChar, charLen, font);
3868 }
3869 NEditFree(free_lineStr);
3870 return width;
3871 }
3872
3873
3874
3875
3876 static int emptyLinesVisible(textDisp *textD)
3877 {
3878 return textD->nVisibleLines >
0 &&
3879 textD->lineStarts[textD->nVisibleLines-
1] == -
1;
3880 }
3881
3882
3883
3884
3885
3886
3887
3888 static void blankSingleCursorProtrusions(textDisp *textD)
3889 {
3890 int x, width, cursorX = textD->cursor->x, cursorY = textD->cursor->y;
3891 int fontWidth = textD->font->maxWidth;
3892 int fontHeight = textD->ascent + textD->descent;
3893 int cursorWidth, left = textD->left, right = left + textD->width;
3894
3895 cursorWidth = (fontWidth/
3) *
2;
3896 if (cursorX >= left-
1 && cursorX <= left + cursorWidth/
2 -
1) {
3897 x = cursorX - cursorWidth/
2;
3898 width = left - x;
3899 }
else if (cursorX >= right - cursorWidth/
2 && cursorX <= right) {
3900 x = right;
3901 width = cursorX + cursorWidth/
2 +
2 - right;
3902 }
else
3903 return;
3904
3905 XClearArea(XtDisplay(textD->w), XtWindow(textD->w), x, cursorY,
3906 width, fontHeight, False);
3907 }
3908
3909 static void blankCursorProtrusions(textDisp *textD) {
3910 if(textD->mcursorSize ==
1) {
3911 blankSingleCursorProtrusions(textD);
3912 }
else {
3913 textCursor *origCursor = textD->cursor;
3914 for(
int i=
0;i<textD->mcursorSize;i++) {
3915 textD->cursor = textD->multicursor + i;
3916 blankSingleCursorProtrusions(textD);
3917 }
3918 textD->cursor = origCursor;
3919 }
3920 }
3921
3922
3923
3924
3925
3926 static void allocateFixedFontGCs(textDisp *textD, Pixel bgPixel, Pixel fgPixel)
3927 {
3928 textD->gc = allocateGC(textD->w, GCForeground | GCBackground,
3929 fgPixel, bgPixel,
0, GCClipMask, GCArcMode);
3930 }
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941 static GC allocateGC(Widget w,
unsigned long valueMask,
3942 unsigned long foreground,
unsigned long background, Font font,
3943 unsigned long dynamicMask,
unsigned long dontCareMask)
3944 {
3945 XGCValues gcValues;
3946
3947 gcValues.font = font;
3948 gcValues.background = background;
3949 gcValues.foreground = foreground;
3950 #if defined(XlibSpecificationRelease) && XlibSpecificationRelease >
4
3951 return XtAllocateGC(w,
0, valueMask, &gcValues, dynamicMask,
3952 dontCareMask);
3953 #else
3954 return XCreateGC(XtDisplay(w), RootWindowOfScreen(XtScreen(w)),
3955 valueMask, &gcValues);
3956 #endif
3957 }
3958
3959
3960
3961
3962 static void releaseGC(Widget w,
GC gc)
3963 {
3964 #if defined(XlibSpecificationRelease) && XlibSpecificationRelease >
4
3965 XtReleaseGC(w, gc);
3966 #else
3967 XFreeGC(XtDisplay(w), gc);
3968 #endif
3969 }
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979 static void resetClipRectangles(textDisp *textD)
3980 {
3981 XRectangle clipRect;
3982 Display *display = XtDisplay(textD->w);
3983
3984 clipRect.x = textD->left;
3985 clipRect.y = textD->top;
3986 clipRect.width = textD->width;
3987 clipRect.height = textD->height - textD->height %
3988 (textD->ascent + textD->descent);
3989
3990 XSetClipRectangles(display, textD->gc,
0,
0,
3991 &clipRect,
1, Unsorted);
3992
3993 if(textD->d) {
3994 XftDrawSetClipRectangles(textD->d,
0,
0, &clipRect,
1);
3995 }
3996 }
3997
3998
3999
4000
4001
4002 static int visLineLength(textDisp *textD,
int visLineNum)
4003 {
4004 int nextLineStart, lineStartPos = textD->lineStarts[visLineNum];
4005
4006 if (lineStartPos == -
1)
4007 return 0;
4008 if (visLineNum+
1 >= textD->nVisibleLines)
4009 return textD->lastChar - lineStartPos;
4010 nextLineStart = textD->lineStarts[visLineNum+
1];
4011 if (nextLineStart == -
1)
4012 return textD->lastChar - lineStartPos;
4013 if (wrapUsesCharacter(textD, nextLineStart-
1))
4014 return nextLineStart-
1 - lineStartPos;
4015 return nextLineStart - lineStartPos;
4016 }
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027 static int findWrapRange(textDisp *textD,
const char *deletedText,
int pos,
4028 int nInserted,
int nDeleted,
int *modRangeStart,
int *modRangeEnd,
4029 int *linesInserted,
int *linesDeleted)
4030 {
4031 int length, retPos, retLines, retLineStart, retLineEnd;
4032 textBuffer *deletedTextBuf, *buf = textD->buffer;
4033 int nVisLines = textD->nVisibleLines;
4034 int *lineStarts = textD->lineStarts;
4035 int countFrom, countTo, lineStart, adjLineStart, i;
4036 int visLineNum =
0, nLines =
0;
4037 int nl =
0;
4038
4039
4040
4041
4042
4043
4044 if (pos >= textD->firstChar && pos <= textD->lastChar) {
4045 for (i=nVisLines-
1; i>
0; i--) {
4046 if (lineStarts[i] != -
1 && pos >= lineStarts[i])
4047 break;
4048 }
4049 if (i >
0) {
4050 countFrom = lineStarts[i-
1];
4051 visLineNum = i-
1;
4052 }
else
4053 countFrom = BufStartOfLine(buf, pos);
4054 }
else
4055 countFrom = BufStartOfLine(buf, pos);
4056
4057
4058
4059
4060
4061
4062
4063 lineStart = countFrom;
4064 *modRangeStart = countFrom;
4065 while (True) {
4066
4067
4068
4069 wrappedLineCounter(textD, buf, lineStart, buf->length,
1, True,
0,
4070 &retPos, &retLines, &retLineStart, &retLineEnd,
NULL);
4071 if(pos == retLineEnd) {
4072 nl =
1;
4073 }
4074 if (retPos >= buf->length) {
4075 countTo = buf->length;
4076 *modRangeEnd = countTo;
4077 if (retPos != retLineEnd)
4078 nLines++;
4079 break;
4080 }
else
4081 lineStart = retPos;
4082 nLines++;
4083 if (lineStart > pos + nInserted &&
4084 BufGetCharacter(buf, lineStart-
1) ==
'\n') {
4085 countTo = lineStart;
4086 *modRangeEnd = lineStart;
4087 break;
4088 }
4089
4090
4091
4092
4093
4094
4095
4096 if (textD->suppressResync)
4097 continue;
4098
4099
4100
4101 if (lineStart <= pos) {
4102 while (visLineNum<nVisLines && lineStarts[visLineNum] < lineStart)
4103 visLineNum++;
4104 if (visLineNum < nVisLines && lineStarts[visLineNum] == lineStart) {
4105 countFrom = lineStart;
4106 nLines =
0;
4107 if (visLineNum+
1 < nVisLines && lineStarts[visLineNum+
1] != -
1)
4108 *modRangeStart = min(pos, lineStarts[visLineNum+
1]-
1);
4109 else
4110 *modRangeStart = countFrom;
4111 }
else
4112 *modRangeStart = min(*modRangeStart, lineStart-
1);
4113 }
4114
4115
4116
4117 else if (lineStart > pos + nInserted) {
4118 adjLineStart = lineStart - nInserted + nDeleted;
4119 while (visLineNum<nVisLines && lineStarts[visLineNum]<adjLineStart)
4120 visLineNum++;
4121 if (visLineNum < nVisLines && lineStarts[visLineNum] != -
1 &&
4122 lineStarts[visLineNum] == adjLineStart) {
4123 countTo = TextDEndOfLine(textD, lineStart, True);
4124 *modRangeEnd = lineStart;
4125 break;
4126 }
4127 }
4128 }
4129 *linesInserted = nLines;
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152 if (textD->suppressResync) {
4153 *linesDeleted = textD->nLinesDeleted;
4154 textD->suppressResync =
0;
4155 return nl;
4156 }
4157
4158 length = (pos-countFrom) + nDeleted +(countTo-(pos+nInserted));
4159 deletedTextBuf = BufCreatePreallocated(length);
4160 if (pos > countFrom)
4161 BufCopyFromBuf(textD->buffer, deletedTextBuf, countFrom, pos,
0);
4162 if (nDeleted !=
0)
4163 BufInsert(deletedTextBuf, pos-countFrom, deletedText);
4164 if (countTo > pos+nInserted)
4165 BufCopyFromBuf(textD->buffer, deletedTextBuf,
4166 pos+nInserted, countTo, pos-countFrom+nDeleted);
4167
4168
4169 wrappedLineCounter(textD, deletedTextBuf,
0, length,
INT_MAX, True,
4170 countFrom, &retPos, &retLines, &retLineStart, &retLineEnd,
4171 NULL);
4172 BufFree(deletedTextBuf);
4173 *linesDeleted = retLines;
4174 textD->suppressResync =
0;
4175
4176 return nl;
4177 }
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191 static void measureDeletedLines(textDisp *textD,
int pos,
int nDeleted)
4192 {
4193 int retPos, retLines, retLineStart, retLineEnd;
4194 textBuffer *buf = textD->buffer;
4195 int nVisLines = textD->nVisibleLines;
4196 int *lineStarts = textD->lineStarts;
4197 int countFrom, lineStart;
4198 int nLines =
0, i;
4199
4200
4201
4202
4203
4204 if (pos >= textD->firstChar && pos <= textD->lastChar) {
4205 for (i=nVisLines-
1; i>
0; i--)
4206 if (lineStarts[i] != -
1 && pos >= lineStarts[i])
4207 break;
4208 if (i >
0) {
4209 countFrom = lineStarts[i-
1];
4210 }
else
4211 countFrom = BufStartOfLine(buf, pos);
4212 }
else
4213 countFrom = BufStartOfLine(buf, pos);
4214
4215
4216
4217
4218
4219
4220 lineStart = countFrom;
4221 while (True) {
4222
4223
4224 wrappedLineCounter(textD, buf, lineStart, buf->length,
1, True,
0,
4225 &retPos, &retLines, &retLineStart, &retLineEnd,
NULL);
4226 if (retPos >= buf->length) {
4227 if (retPos != retLineEnd)
4228 nLines++;
4229 break;
4230 }
else
4231 lineStart = retPos;
4232 nLines++;
4233 if (lineStart > pos + nDeleted &&
4234 BufGetCharacter(buf, lineStart-
1) ==
'\n') {
4235 break;
4236 }
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250 }
4251 textD->nLinesDeleted = nLines;
4252 textD->suppressResync =
1;
4253 }
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273 static void wrappedLineCounter(
const textDisp* textD,
const textBuffer* buf,
4274 int startPos,
int maxPos,
int maxLines,
4275 Boolean startPosIsLineStart,
int styleBufOffset,
4276 int* retPos,
int* retLines,
int* retLineStart,
int* retLineEnd,
4277 Boolean *retWrap)
4278 {
4279 int lineStart, newLineStart =
0, b, p, colNum, wrapMargin;
4280 int maxWidth, width, countPixels, i, foundBreak;
4281 int nLines =
0, tabDist = textD->buffer->tabDist;
4282 FcChar32 c;
4283 char nullSubsChar = textD->buffer->nullSubsChar;
4284 if(retWrap) {
4285 *retWrap = False;
4286 }
4287
4288
4289
4290
4291
4292 if (textD->fixedFontWidth != -
1 || textD->wrapMargin !=
0) {
4293 countPixels = False;
4294 wrapMargin = textD->wrapMargin !=
0 ? textD->wrapMargin :
4295 textD->width / textD->fixedFontWidth;
4296 maxWidth =
INT_MAX;
4297 }
else {
4298 countPixels = True;
4299 wrapMargin =
INT_MAX;
4300 maxWidth = textD->width;
4301 }
4302
4303
4304
4305 if (startPosIsLineStart)
4306 lineStart = startPos;
4307 else
4308 lineStart = TextDStartOfLine(textD, startPos);
4309
4310
4311
4312
4313
4314
4315 colNum =
0;
4316 width =
0;
4317 int inc =
1;
4318 for (p=lineStart; p<buf->length; p+=inc) {
4319 c = getCharacter32(textD, buf, p, &inc);
4320
4321
4322
4323 if ((
char)c ==
'\n') {
4324 if (p >= maxPos) {
4325 *retPos = maxPos;
4326 *retLines = nLines;
4327 *retLineStart = lineStart;
4328 *retLineEnd = maxPos;
4329 return;
4330 }
4331 nLines++;
4332 if (nLines >= maxLines) {
4333 *retPos = p +
1;
4334 *retLines = nLines;
4335 *retLineStart = p +
1;
4336 *retLineEnd = p;
4337 return;
4338 }
4339 lineStart = p +
1;
4340 colNum =
0;
4341 width =
0;
4342 }
else if(c !=
0) {
4343 colNum += BufCharWidth((
char)c, colNum, tabDist, nullSubsChar);
4344 if (countPixels)
4345 width += measurePropChar(textD, c, colNum, p+styleBufOffset);
4346 }
4347
4348
4349
4350 if (colNum > wrapMargin || width > maxWidth) {
4351 if(retWrap) {
4352 *retWrap = True;
4353 retWrap =
NULL;
4354 }
4355
4356 foundBreak = False;
4357
4358 for (b=p; b>=lineStart; b--) {
4359 c = BufGetCharacter(buf, b);
4360 if ((
char)c ==
'\t' || (
char)c ==
' ') {
4361 newLineStart = b +
1;
4362 if (countPixels) {
4363 colNum =
0;
4364 width =
0;
4365 int charLen;
4366 for (i=b+
1; i<p+
1; i+=charLen) {
4367 width += measurePropChar(textD,
4368 getCharacter32(textD, buf, i, &charLen), colNum,
4369 i+styleBufOffset);
4370 colNum++;
4371 }
4372 }
else
4373 colNum = BufCountDispChars(buf, b+
1, p+
1);
4374 foundBreak = True;
4375 break;
4376 }
4377 }
4378 if (!foundBreak) {
4379 newLineStart = max(p, lineStart+
1);
4380 colNum = BufCharWidth((
char)c, colNum, tabDist, nullSubsChar);
4381 if (countPixels)
4382 width = measurePropChar(textD, c, colNum, p+styleBufOffset);
4383 }
4384 if (p >= maxPos) {
4385 *retPos = maxPos;
4386 *retLines = maxPos < newLineStart ? nLines : nLines +
1;
4387 *retLineStart = maxPos < newLineStart ? lineStart :
4388 newLineStart;
4389 *retLineEnd = maxPos;
4390 return;
4391 }
4392 nLines++;
4393 if (nLines >= maxLines) {
4394 *retPos = foundBreak ? b +
1 : max(p, lineStart+
1);
4395 *retLines = nLines;
4396 *retLineStart = lineStart;
4397 *retLineEnd = foundBreak ? b : p;
4398 return;
4399 }
4400 lineStart = newLineStart;
4401 }
4402 }
4403
4404
4405 *retPos = buf->length;
4406 *retLines = nLines;
4407 *retLineStart = lineStart;
4408 *retLineEnd = buf->length;
4409 return;
4410 }
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426 static int measurePropChar(
const textDisp* textD, FcChar32 c,
4427 int colNum,
int pos)
4428 {
4429 int style;
4430 textBuffer *styleBuf = textD->styleBuffer;
4431
4432 NFont *font =
NULL;
4433 if (styleBuf) {
4434 style = (
unsigned char)BufGetCharacter(styleBuf, pos);
4435 if (style == textD->unfinishedStyle) {
4436
4437 (textD->unfinishedHighlightCB)(textD, pos, textD->highlightCBArg);
4438 style = (
unsigned char)BufGetCharacter(styleBuf, pos);
4439 }
4440 if (style &
STYLE_LOOKUP_MASK) {
4441 font = textD->styleTable[(style &
STYLE_LOOKUP_MASK) -
ASCII_A].font;
4442 }
4443 }
4444 if(!font) {
4445 font = textD->font;
4446 }
4447
4448 int charLen;
4449 FcChar32 expChar[
MAX_EXP_CHAR_LEN];
4450 if(c <
128) {
4451 charLen = BufExpandCharacter4(c, colNum, expChar,
4452 textD->buffer->tabDist, textD->buffer->nullSubsChar);
4453
4454 if(font->minWidth == font->maxWidth) {
4455 return font->minWidth;
4456 }
else {
4457 XGlyphInfo extents;
4458 XftTextExtents32(XtDisplay(textD->w), font->fonts->font, expChar, charLen, &extents);
4459 return extents.xOff;
4460 }
4461 }
else {
4462 charLen =
1;
4463 expChar[
0] = c;
4464 }
4465
4466 return charWidth4(textD, expChar, charLen, font);
4467 }
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479 static void findLineEnd(textDisp *textD,
int startPos,
int startPosIsLineStart,
4480 int *lineEnd,
int *nextLineStart)
4481 {
4482 int retLines, retLineStart;
4483
4484
4485 if (!textD->continuousWrap) {
4486 *lineEnd = BufEndOfLine(textD->buffer, startPos);
4487 *nextLineStart = min(textD->buffer->length, *lineEnd +
1);
4488 return;
4489 }
4490
4491
4492 wrappedLineCounter(textD, textD->buffer, startPos, textD->buffer->length,
4493 1, startPosIsLineStart,
0, nextLineStart, &retLines,
4494 &retLineStart, lineEnd,
NULL);
4495 return;
4496 }
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514 static int wrapUsesCharacter(textDisp *textD,
int lineEndPos)
4515 {
4516 char c;
4517
4518 if (!textD->continuousWrap || lineEndPos == textD->buffer->length)
4519 return True;
4520
4521 c = BufGetCharacter(textD->buffer, lineEndPos);
4522 return c ==
'\n' || ((c ==
'\t' || c ==
' ') &&
4523 lineEndPos +
1 != textD->buffer->length);
4524 }
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534 static void hideOrShowHScrollBar(textDisp *textD)
4535 {
4536 if (textD->continuousWrap && (textD->wrapMargin ==
0 || textD->wrapMargin *
4537 FontDefault(textD->font)->max_advance_width < textD->width))
4538 XtUnmanageChild(textD->hScrollBar);
4539 else
4540 XtManageChild(textD->hScrollBar);
4541 }
4542
4543
4544
4545
4546
4547 static int rangeTouchesRectSel(selection *sel,
int rangeStart,
int rangeEnd)
4548 {
4549 return sel->selected && sel->rectangular && sel->end >= rangeStart &&
4550 sel->start <= rangeEnd;
4551 }
4552
4553
4554
4555
4556
4557
4558 static void extendRangeForStyleMods(textDisp *textD,
int *start,
int *end)
4559 {
4560 selection *sel = &textD->styleBuffer->primary;
4561 int extended = False;
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573 if (sel->selected) {
4574 if (sel->start < *start) {
4575 *start = sel->start;
4576 extended = True;
4577 }
4578 if (sel->end > *end) {
4579 *end = sel->end;
4580 extended = True;
4581 }
4582 }
4583
4584
4585
4586
4587 if (textD->fixedFontWidth == -
1 && extended)
4588 *end = BufEndOfLine(textD->buffer, *end) +
1;
4589 }
4590
4591
4592
4593
4594
4595
4596
4597
4598 static XftColor allocBGColor(Widget w,
char *colorName,
int *ok)
4599 {
4600 int r,g,b;
4601 *ok =
1;
4602 XftColor color;
4603 color.pixel = AllocColor(w, colorName, &r, &g, &b);
4604 color.color.red = r;
4605 color.color.green = g;
4606 color.color.blue = b;
4607 color.color.alpha = 0xFFFF;
4608 return color;
4609 }
4610
4611 static XftColor* getRangesetColor(textDisp *textD,
int ind, XftColor *bground)
4612 {
4613 textBuffer *buf;
4614 RangesetTable *tab;
4615 XftColor color;
4616 char *color_name;
4617 int valid;
4618
4619 if (ind >
0) {
4620 ind--;
4621 buf = textD->buffer;
4622 tab = buf->rangesetTable;
4623
4624 Rangeset *rangeset =
NULL;
4625 valid = RangesetTableGetColorValid(tab, ind, &color, &rangeset);
4626 if (valid ==
0) {
4627 color_name = RangesetTableGetColorName(tab, ind);
4628 if (color_name)
4629 color = allocBGColor(textD->w, color_name, &valid);
4630 rangeset = RangesetTableAssignColorPixel(tab, ind, color, valid);
4631 }
4632 if (valid >
0) {
4633 return RangesetGetColor(rangeset);
4634 }
4635 }
4636 return bground;
4637 }
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649 void TextDSetupBGClasses(Widget w, XmString str, XftColor **pp_bgClassPixel,
4650 unsigned char **pp_bgClass, XftColor bgPixelDefault)
4651 {
4652 unsigned char bgClass[
256];
4653 XftColor bgClassPixel[
256];
4654 int class_no =
0;
4655 char *semicol;
4656 char *s = (
char *)str;
4657 size_t was_semicol;
4658 int lo, hi, dummy;
4659 char *pos;
4660 Boolean is_good = True;
4661
4662 NEditFree(*pp_bgClass);
4663 NEditFree(*pp_bgClassPixel);
4664
4665 *pp_bgClassPixel =
NULL;
4666 *pp_bgClass =
NULL;
4667
4668 if (!s)
4669 return;
4670
4671
4672 memset(bgClassPixel,
0,
sizeof bgClassPixel);
4673 memset(bgClass,
0,
sizeof bgClass);
4674 bgClassPixel[
0] = bgPixelDefault;
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699 while (s && class_no <
255) {
4700 class_no++;
4701 was_semicol =
0;
4702 is_good = True;
4703 if ((semicol = (
char *)strchr(s,
';'))) {
4704 *semicol =
'\0';
4705 was_semicol =
1;
4706 }
4707
4708
4709
4710 for (lo = hi = strtol(s, &pos,
0);
4711 is_good;
4712 lo = hi = strtol(pos +
1, &pos,
0)) {
4713 if (pos && *pos ==
'-')
4714 hi = strtol(pos +
1, &pos,
0);
4715 is_good = (pos &&
0 <= lo && lo <= hi && hi <=
255);
4716 if (is_good)
4717 while (lo <= hi)
4718 bgClass[lo++] = (
unsigned char)class_no;
4719 if (*pos !=
',')
4720 break;
4721 }
4722 if ((is_good = (is_good && *pos ==
':'))) {
4723 is_good = (*pos++ !=
'\0');
4724 bgClassPixel[class_no] = allocBGColor(w, pos, &dummy);
4725 }
4726 if (!is_good) {
4727
4728 }
4729
4730
4731 if (was_semicol)
4732 *semicol =
';';
4733 s = semicol + was_semicol;
4734 }
4735
4736
4737
4738 class_no++;
4739 *pp_bgClass = (
unsigned char *)NEditMalloc(
256);
4740 *pp_bgClassPixel = (XftColor *)NEditMalloc(class_no *
sizeof (XftColor));
4741 if (!*pp_bgClass || !*pp_bgClassPixel) {
4742 NEditFree(*pp_bgClass);
4743 NEditFree(*pp_bgClassPixel);
4744 return;
4745 }
4746 memcpy(*pp_bgClass, bgClass,
256);
4747 memcpy(*pp_bgClassPixel, bgClassPixel, class_no *
sizeof (XftColor));
4748 }
4749
4750
4751 void TextDSetHighlightCursorLine(textDisp *textD, Boolean state)
4752 {
4753 textD->highlightCursorLine = state;
4754 }
4755
4756 void TextDSetIndentRainbow(textDisp *textD, Boolean indentRainbow)
4757 {
4758 textD->indentRainbow = indentRainbow;
4759 }
4760
4761
4762 #define ANSI_ESC_MAX_PARAM 16
4763 #define ANSI_ESC_MAX_PARAM_LEN 4
4764
4765 #define ANSI_ESC_RESET 0
4766 #define ANSI_ESC_BOLD 1
4767 #define ANSI_ESC_ITALIC 3
4768 #define ANSI_ESC_RESET_BOLD 22
4769 #define ANSI_ESC_RESET_ITALIC 23
4770
4771 #define ANSI_STYLE_SET(style, value)
if(style <
0) style = value
4772
4773
4774
4775
4776 static int parseEscapeSequence(textBuffer *buf,
size_t pos, ansiStyle *style)
4777 {
4778 char c1 = BufGetCharacter(buf, pos);
4779 char c2 = BufGetCharacter(buf, pos+
1);
4780 if(c1 !=
'\e' || c2 !=
'[')
return 0;
4781
4782 int param[
ANSI_ESC_MAX_PARAM];
4783 int nparam =
0;
4784
4785
4786 char paramDig[
ANSI_ESC_MAX_PARAM_LEN];
4787 int paramDigLen =
0;
4788
4789 size_t i = pos+
2;
4790 while(nparam <
ANSI_ESC_MAX_PARAM) {
4791 char c = BufGetCharacter(buf, i++);
4792 if(c >=
'0' && c <=
'9') {
4793 if(paramDigLen >=
ANSI_ESC_MAX_PARAM_LEN)
break;
4794 paramDig[paramDigLen++] = c -
'0';
4795 }
else {
4796 int iParam =
0;
4797 int mul =
1;
4798 for(
int j=paramDigLen-
1;j>=
0;j--) {
4799 iParam += paramDig[j] * mul;
4800 mul *=
10;
4801 }
4802
4803 param[nparam++] = iParam;
4804
4805 paramDigLen =
0;
4806 if(c !=
';')
break;
4807 }
4808 }
4809
4810
4811 for(
int k=
0;k<nparam;k++) {
4812 int p = param[k];
4813
4814 switch(p) {
4815 case ANSI_ESC_RESET: {
4816 ANSI_STYLE_SET(style->fg,
0);
4817 ANSI_STYLE_SET(style->bg,
0);
4818 ANSI_STYLE_SET(style->bold,
0);
4819 ANSI_STYLE_SET(style->italic,
0);
4820 k = nparam;
4821 break;
4822 }
4823 case ANSI_ESC_BOLD: {
4824 ANSI_STYLE_SET(style->bold,
1);
4825 break;
4826 }
4827 case ANSI_ESC_ITALIC: {
4828 ANSI_STYLE_SET(style->italic,
1);
4829 break;
4830 }
4831 case ANSI_ESC_RESET_BOLD: {
4832 ANSI_STYLE_SET(style->bold,
0);
4833 break;
4834 }
4835 case ANSI_ESC_RESET_ITALIC: {
4836 ANSI_STYLE_SET(style->bold,
0);
4837 break;
4838 }
4839 default: {
4840 if((p >=
30 && p <=
39) || (p >=
90 && p <=
97)) {
4841 ANSI_STYLE_SET(style->fg, p);
4842 }
else if((p >=
40 && p <=
49) || (p >=
100 && p <=
107)) {
4843 ANSI_STYLE_SET(style->bg, p);
4844 }
4845 break;
4846 }
4847 }
4848 }
4849
4850
4851 if(style->fg != -
1 && style->bg != -
1 && style->bold != -
1 && style->italic) {
4852 return 1;
4853 }
4854
4855
4856 return 0;
4857 }
4858
4859 static void extendAnsiStyle(ansiStyle *style, ansiStyle *ext)
4860 {
4861 if(ext->fg >=
0) {
4862 style->fg = ext->fg;
4863 }
4864 if(ext->bg >=
0) {
4865 style->bg = ext->bg;
4866 }
4867 if(ext->bold >=
0) style->bold = ext->bold;
4868 if(ext->italic >=
0) style->italic = ext->italic;
4869 }
4870
4871 static void findActiveAnsiStyle(textDisp *textD,
ssize_t pos, ansiStyle *style)
4872 {
4873 textBuffer *buf = textD->buffer;
4874 ssize_t prev_esc;
4875 size_t prev_esc_pos;
4876 BufEscPos2Index(buf,
0,
0, pos, &prev_esc, &prev_esc_pos);
4877 if(prev_esc <
0) {
4878 return;
4879 }
4880
4881 for(
ssize_t i=prev_esc;i>=
0;i--) {
4882 if(parseEscapeSequence(buf, prev_esc_pos, style)) {
4883 break;
4884 }
4885 prev_esc_pos -= buf->ansi_escpos[i];
4886 }
4887 }
4888
4889 static void ansiFgToColorIndex(textDisp *textD,
short fg, XftColor *color)
4890 {
4891 if(fg >=
30 && fg <=
37) {
4892 *color = textD->colorProfile->ansiColors[fg-
30];
4893 }
else if(fg >=
90 && fg <=
97) {
4894 *color = textD->colorProfile->ansiColors[fg-
90];
4895 }
4896 }
4897
4898 static void ansiBgToColorIndex(textDisp *textD,
short bg, XftColor *color)
4899 {
4900 if(bg >=
40 && bg <=
47) {
4901 *color = textD->colorProfile->ansiColors[bg-
40];
4902 }
else if(bg >=
100 && bg <=
107) {
4903 *color = textD->colorProfile->ansiColors[bg-
100];
4904 }
4905 }
4906
4907
4908 static void getFontMinMax(NFont *font,
int *min,
int *max) {
4909 XftFont *xftFont = FontDefault(font);
4910 int fontMin = xftFont->max_advance_width;
4911 int fontMax =
0;
4912
4913 for(
int i=
32;i<
127;i++) {
4914 XGlyphInfo extents;
4915 FcChar8 c = i;
4916 XftTextExtents8(font->display, xftFont, &c,
1, &extents);
4917 if(extents.xOff < fontMin) {
4918 fontMin = extents.xOff;
4919 }
4920 if(extents.xOff > fontMax) {
4921 fontMax = extents.xOff;
4922 }
4923 }
4924
4925 *min = fontMin;
4926 *max = fontMax;
4927 }
4928
4929 NFont *FontCreate(Display *dp, FcPattern *pattern)
4930 {
4931 if(!pattern) {
4932 return NULL;
4933 }
4934 FcResult result;
4935 pattern = FcPatternDuplicate(pattern);
4936 FcPattern *match = XftFontMatch(dp, DefaultScreen(dp), pattern, &result);
4937
4938 double sz =
0;
4939 result = FcPatternGetDouble (pattern,
FC_SIZE,
0, &sz);
4940 if(result != FcResultMatch) {
4941 FcPatternGetDouble (match,
FC_SIZE,
0, &sz);
4942 }
4943
4944 XftFont *defaultFont = XftFontOpenPattern(dp, match);
4945 if(!defaultFont) {
4946 FcPatternDestroy(match);
4947 return NULL;
4948 }
4949
4950 NFont *font = NEditMalloc(
sizeof(NFont));
4951 font->display = dp;
4952 font->pattern = pattern;
4953 font->fail =
NULL;
4954 font->size = sz;
4955 font->ref =
1;
4956
4957 NFontList *list = NEditMalloc(
sizeof(NFontList));
4958 list->font = defaultFont;
4959 list->next =
NULL;
4960 font->fonts = list;
4961
4962 getFontMinMax(font, &font->minWidth, &font->maxWidth);
4963
4964 return font;
4965 }
4966
4967 NFont *FontFromName(Display *dp,
const char *name)
4968 {
4969 FcPattern *pattern = FcNameParse((FcChar8*)name);
4970 if(!pattern) {
4971 return NULL;
4972 }
4973 NFont *font = FontCreate(dp, pattern);
4974 FcPatternDestroy(pattern);
4975 return font;
4976 }
4977
4978 XftFont *FontListAddFontForChar(NFont *f, FcChar32 c)
4979 {
4980
4981 FcCharSet *charset = FcCharSetCreate();
4982 FcValue value;
4983 value.type = FcTypeCharSet;
4984 value.u.c = charset;
4985 FcCharSetAddChar(charset, c);
4986 if(!FcCharSetHasChar(charset, c)) {
4987 FcCharSetDestroy(charset);
4988 return f->fonts->font;
4989 }
4990
4991
4992 FcPattern *pattern = FcPatternDuplicate(f->pattern);
4993 FcPatternAdd(pattern,
FC_CHARSET, value,
0);
4994 FcResult result;
4995 FcPattern *match = XftFontMatch (
4996 f->display, DefaultScreen(f->display), pattern, &result);
4997 if(!match) {
4998 FcPatternDestroy(pattern);
4999 FontAddFail(f, charset);
5000 return f->fonts->font;
5001 }
5002
5003 XftFont *newFont = XftFontOpenPattern(f->display, match);
5004 if(!newFont || !FcCharSetHasChar(newFont->charset, c)) {
5005 FcPatternDestroy(pattern);
5006 FcPatternDestroy(match);
5007 if(newFont) {
5008 XftFontClose(f->display, newFont);
5009 }
5010 FontAddFail(f, charset);
5011 return f->fonts->font;
5012 }
5013
5014 FcCharSetDestroy(charset);
5015
5016 NFontList *newElm = NEditMalloc(
sizeof(NFontList));
5017 newElm->font = newFont;
5018 newElm->next =
NULL;
5019
5020 NFontList *elm = f->fonts;
5021 NFontList *last =
NULL;
5022 while(elm) {
5023 last = elm;
5024 elm = elm->next;
5025 }
5026 last->next = newElm;
5027
5028
5029 return newFont;
5030 }
5031
5032 XftFont *FindFont(NFont *f, FcChar32 c)
5033 {
5034 if(c <
128) {
5035 return f->fonts->font;
5036 }
5037
5038
5039
5040 NCharSetList *fail = f->fail;
5041 while(fail) {
5042 if(FcCharSetHasChar(fail->charset, c)) {
5043 return f->fonts->font;
5044 }
5045 fail = fail->next;
5046
5047 }
5048
5049
5050 NFontList *elm = f->fonts;
5051 while(elm) {
5052 if(FcCharSetHasChar(elm->font->charset, c)) {
5053 return elm->font;
5054 }
5055 elm = elm->next;
5056 }
5057
5058
5059 return FontListAddFontForChar(f, c);
5060 }
5061
5062 XftFont *FontDefault(NFont *f) {
5063 return f->fonts->font;
5064 }
5065
5066 void FontAddFail(NFont *f, FcCharSet *c)
5067 {
5068 NCharSetList *elm = f->fail;
5069 NCharSetList *last = elm;
5070 while(elm) {
5071 last = elm;
5072 elm = elm->next;
5073 }
5074
5075 NCharSetList *newElm = NEditMalloc(
sizeof(NCharSetList));
5076 newElm->charset = c;
5077 newElm->next =
NULL;
5078 if(last) {
5079 last->next = newElm;
5080 }
else {
5081 f->fail = newElm;
5082 }
5083 }
5084
5085 void FontDestroy(NFont *f)
5086 {
5087 NCharSetList *c = f->fail;
5088 NCharSetList *nc;
5089 while(c) {
5090 FcCharSetDestroy(c->charset);
5091 nc = c->next;
5092 NEditFree(c);
5093 c = nc;
5094 }
5095
5096 NFontList *l = f->fonts;
5097 NFontList *nl;
5098 while(l) {
5099 XftFontClose(f->display, l->font);
5100 nl = l->next;
5101 NEditFree(l);
5102 l = nl;
5103 }
5104
5105 FcPatternDestroy(f->pattern);
5106 NEditFree(f);
5107 }
5108
5109 NFont *FontRef(NFont *font) {
5110 font->ref++;
5111 return font;
5112 }
5113
5114 void FontUnref(NFont *font) {
5115 if(--font->ref ==
0) {
5116 FontDestroy(font);
5117 }
5118 }
5119