2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 #ifdef VERBOSE_REV_INFO
25 static char rcs_id[] = "$XConsortium: TermPrimRenderMb.c /main/1 1996/04/21 19:19:05 drk $";
26 #endif /* VERBOSE_REV_INFO */
30 * (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company *
31 * (c) Copyright 1993, 1994, 1996 International Business Machines Corp. *
32 * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc. *
33 * (c) Copyright 1993, 1994, 1996 Novell, Inc. *
34 * (c) Copyright 1996 Digital Equipment Corporation. *
35 * (c) Copyright 1996 FUJITSU LIMITED. *
36 * (c) Copyright 1996 Hitachi. *
40 ** This file contains the multi-byte character versions of the render routines.
43 #include "TermHeader.h"
44 #include "TermPrimDebug.h"
45 #include "TermPrimP.h"
46 #include "TermPrimData.h"
47 #include "TermPrimLineDraw.h"
48 #include "TermPrimOSDepI.h"
49 #include "TermPrimBufferP.h"
50 #include "TermPrimRenderP.h"
51 #include "TermPrimSelect.h"
52 #include "TermPrimSelectP.h"
57 _DtTermPrimRefreshTextWc(Widget w, short startColumn, short startRow,
58 short endColumn, short endRow)
60 DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
61 struct termData *tpd = tw->term.tpd;
62 TermBuffer tBuffer = tpd->termBuffer;
68 int currentColorPair = 0;
70 short chunkStartColumn;
73 short thisStartColumn;
75 enhValues enhancements;
78 unsigned long valueMask;
81 TermEnhInfoRec enhInfo;
82 Boolean checkSelection = False;
86 XmTextPosition begin, end;
87 TermCharInfoRec startCharInfo;
89 DebugF('t', 0, fprintf(stderr, ">>_DtTermPrimRefreshTextWc() starting\n"));
90 DebugF('t', 0, fprintf(stderr,
91 ">>_DtTermPrimRefreshTextWc() startCol=%hd startRow=%hd endCol=%hd endRow=%hd\n",
92 startColumn, startRow, endColumn, endRow));
94 /* clip start/end x/y... */
99 if (endColumn >= tw->term.columns)
100 endColumn = tw->term.columns - 1;
101 if (endRow >= tw->term.rows)
102 endRow = tw->term.rows - 1;
105 ** don't display if we are in jump scroll and in the process
106 ** of scrolling and inside the scroll region...
108 if (tw->term.jumpScroll && tpd->scroll.jump.scrolled) {
109 /* set all the scrollRefreshRows flags... */
110 for (; startRow <= endRow; startRow++) {
111 tpd->scrollRefreshRows[startRow] = True;
116 ">>_DtTermPrimRefreshTextWc() jump scroll in progress, no render\n"));
120 if (!tpd->renderGC.gc) {
121 /* get a drawImageString GC... */
125 /***********************************************************
128 /* set the GC fg and bg... */
129 values.foreground = tw->primitive.foreground;
130 values.background = tw->core.background_pixel;
132 tpd->renderGC.gc = XCreateGC(XtDisplay(w), XtWindow(w),
133 GCForeground | GCBackground, &values);
135 /* set the GC cache values... */
136 tpd->renderGC.foreground = values.foreground;
137 tpd->renderGC.background = values.background;
138 tpd->renderGC.fid = (Font) 0;
140 /***********************************************************
143 values.foreground = tw->core.background_pixel;
144 values.background = tw->primitive.foreground;
146 tpd->renderReverseGC.gc = XCreateGC(XtDisplay(w), XtWindow(w),
147 GCForeground | GCBackground, &values);
149 /* set the GC cache values... */
150 tpd->renderReverseGC.foreground = values.foreground;
151 tpd->renderReverseGC.background = values.background;
152 tpd->renderReverseGC.fid = (Font) 0;
154 /***********************************************************
157 values.foreground = tw->core.background_pixel;
158 values.background = tw->primitive.foreground;
159 tpd->clearGC.gc = XCreateGC(XtDisplay(w), XtWindow(w),
160 GCForeground | GCBackground, &values);
162 /* set the GC cache values... */
163 tpd->clearGC.foreground = values.foreground;
164 tpd->clearGC.background = values.background;
165 tpd->clearGC.fid = (Font) 0;
168 /* clip start/end x/y... */
169 if (endColumn >= tw->term.columns)
170 endColumn = tw->term.columns - 1;
171 if (endRow >= tw->term.rows)
172 endRow = tw->term.rows - 1;
174 for (; startRow <= endRow; startRow++) {
175 /* if we are refreshing a full line, then we can clear the
176 * scrollRefreshRows flag for this line...
178 if ((startColumn == 0) && (endColumn >= tw->term.columns - 1)) {
179 tpd->scrollRefreshRows[startRow] = False;
182 lineNum = startRow + tpd->topRow;
184 /* are we in the selected area?... */
185 if (tpd->useHistoryBuffer)
187 if (_DtTermPrimSelectGetSelection(w, &begin, &end) &&
189 (lineNum >= (begin / (tpd->selectInfo->columns + 1)) -
190 tpd->lastUsedHistoryRow) &&
191 (lineNum <= (end / (tpd->selectInfo->columns + 1)) -
192 tpd->lastUsedHistoryRow)) {
193 checkSelection = True;
195 checkSelection = False;
200 if (_DtTermPrimSelectGetSelection(w, &begin, &end) &&
202 (lineNum >= (begin / (tpd->selectInfo->columns + 1))) &&
203 (lineNum <= (end / (tpd->selectInfo->columns + 1)))) {
204 checkSelection = True;
206 checkSelection = False;
210 if (startColumn > endColumn) {
211 /* nothing to render on this line... */
215 if (lineNum >= tpd->lastUsedRow) {
216 /* we are pointing to empty screen space below the last used
217 * line of the display...
220 linePtr = (wchar_t) 0;
221 thisStartColumn = startColumn;
222 thisEndColumn = endColumn;
223 } else if (lineNum < 0) {
224 if ((tpd->useHistoryBuffer) &&
225 (-lineNum <= tpd->lastUsedHistoryRow)) {
226 /* get a line out of the history buffer... */
227 lineWidth = _DtTermPrimBufferGetLineWidth(tpd->historyBuffer,
228 tpd->lastUsedHistoryRow + lineNum);
229 if ((startColumn < lineWidth) &&
230 _DtTermPrimGetCharacterInfo(tpd->historyBuffer,
231 tpd->lastUsedHistoryRow + lineNum,
232 startColumn, &startCharInfo)) {
233 thisStartColumn = startCharInfo.startCol;
235 /* past the last character in this line... */
236 thisStartColumn = startColumn;
239 /* get the line width and a pointer to the data... */
240 thisEndColumn = endColumn;
241 lineWidth = MAX(0, MIN(thisEndColumn - thisStartColumn + 1,
242 lineWidth - startColumn));
243 linePtr = startCharInfo.u.pwc;
245 /* we are above the history buffer. Should not happen, but...
248 linePtr = (wchar_t) 0;
251 /* adjust startColumn to point to the first column for the
254 lineWidth = _DtTermPrimBufferGetLineWidth(tBuffer, lineNum);
255 if ((startColumn < lineWidth) &&
256 _DtTermPrimGetCharacterInfo(tBuffer, lineNum, startColumn,
258 thisStartColumn = startCharInfo.startCol;
260 /* past the last character in this line... */
261 thisStartColumn = startColumn;
264 /* get the line width and a pointer to the data... */
265 thisEndColumn = endColumn;
266 lineWidth = MAX(0, MIN(thisEndColumn - thisStartColumn + 1,
267 lineWidth - thisStartColumn));
268 linePtr = startCharInfo.u.pwc;
271 chunkStartColumn = thisStartColumn;
272 while (lineWidth > 0) {
273 /* get the enhancement values for the first chunk of the
277 (void) _DtTermPrimBufferGetEnhancement(tBuffer,
280 chunkStartColumn, /* col */
281 &enhancements, /* enhancements */
282 &chunkWidth, /* width */
283 countAll); /* countWhich */
285 /* get it from the history buffer... */
286 (void) _DtTermPrimBufferGetEnhancement(tpd->historyBuffer,
288 tpd->lastUsedHistoryRow + lineNum,
290 chunkStartColumn, /* col */
291 &enhancements, /* enhancements */
292 &chunkWidth, /* width */
293 countAll); /* countWhich */
296 /* clip chunkWidth... */
297 if (chunkWidth > lineWidth)
298 chunkWidth = lineWidth;
300 /* Are we in the selection area?
301 * _DtTermPrimSelectIsInSelection clips the chunkWidth to
302 * the end of the selection if we are...
304 if (checkSelection &&
305 _DtTermPrimSelectIsInSelection(w, lineNum, chunkStartColumn,
306 chunkWidth, &chunkWidth)) {
312 /* walk through the linePtr and figure out how many
313 * wide characters we need to render to fill out this
314 * chunk, and if the end of this chunk is in the middle
315 * of a wide character, bump the chunkWidth one column.
317 for (chunkLineWidth = 0, wc = linePtr;
318 chunkLineWidth < chunkWidth;
319 chunkLineWidth += i1, wc++) {
320 if ((i1 = wcwidth(*wc)) <= 0) {
321 /* take care of null characters... */
325 /* adjust for a multi-column character that spans the line
328 if (chunkLineWidth > chunkWidth) {
329 chunkWidth = chunkLineWidth;
331 /* set reasonable defaults for our render info... */
332 enhInfo.fg = tw->primitive.foreground;
333 enhInfo.bg = tw->core.background_pixel;
334 enhInfo.font = tpd->defaultTermFont;
335 enhInfo.flags = (unsigned long) 0;
337 /* set our font and color from the enhancements... */
338 if (ENH_PROC(tBuffer)) {
339 (void) (*(ENH_PROC(tBuffer)))(w, enhancements, &enhInfo);
342 /* are we in the selection area?... */
344 /* flip fg and bg... */
345 tmpPixel = enhInfo.fg;
346 enhInfo.fg = enhInfo.bg;
347 enhInfo.bg = tmpPixel;
350 /* if secure, we will use a XFillRectangle, and we need
351 * foreground set to the background...
354 /* set the renderGC... */
355 valueMask = (unsigned long) 0;
356 if (TermIS_SECURE(enhInfo.flags)) {
357 /* render secure video locally...
359 if (tpd->renderReverseGC.foreground != enhInfo.bg) {
360 tpd->renderReverseGC.foreground = enhInfo.bg;
361 values.foreground = enhInfo.bg;
362 valueMask |= GCForeground;
365 (void) XChangeGC(XtDisplay(w), tpd->renderReverseGC.gc,
368 (void) XFillRectangle(XtDisplay(w),
370 tpd->renderReverseGC.gc,
371 chunkStartColumn * tpd->cellWidth + tpd->offsetX,
372 startRow * tpd->cellHeight + tpd->offsetY,
373 tpd->cellWidth * chunkWidth,
376 /* underline as well... */
377 if (TermIS_UNDERLINE(enhInfo.flags)) {
378 valueMask = (unsigned long) 0;
379 if (tpd->renderGC.foreground != enhInfo.fg) {
380 tpd->renderGC.foreground = enhInfo.fg;
381 values.foreground = enhInfo.fg;
382 valueMask |= GCForeground;
385 (void) XChangeGC(XtDisplay(w), tpd->renderGC.gc,
388 (void) XDrawLine(XtDisplay(w),
390 XtWindow(w), /* Drawable */
391 tpd->renderGC.gc, /* GC */
392 chunkStartColumn * tpd->cellWidth + tpd->offsetX,
394 startRow * tpd->cellHeight + tpd->offsetY +
397 (chunkStartColumn + chunkWidth) * tpd->cellWidth +
398 tpd->offsetX, /* X2 */
399 startRow * tpd->cellHeight + tpd->offsetY +
400 tpd->cellHeight - 1);
404 (void) _DtTermPrimRenderText(
406 enhInfo.font, /* TermFont */
407 enhInfo.fg, /* fg Pixel */
408 enhInfo.bg, /* bg Pixel */
409 enhInfo.flags, /* flags */
410 chunkStartColumn * tpd->cellWidth + tpd->offsetX,
412 startRow * tpd->cellHeight + tpd->offsetY,
414 /*DKS: this probably should be changed... */
415 (termChar *) linePtr, /* string */
416 wc - linePtr); /* width */
418 chunkStartColumn += chunkWidth;
419 lineWidth -= chunkWidth;
423 /* clear any extra space in the line. chunkStartColumn now points to
424 * the end of the line, and lineWidth == 0...
426 while (thisEndColumn - chunkStartColumn >= 0) {
427 chunkWidth = thisEndColumn - chunkStartColumn + 1;
428 if (checkSelection &&
429 _DtTermPrimSelectIsInSelection(w, lineNum, chunkStartColumn,
430 chunkWidth, &chunkWidth)) {
431 /* use the render gc set to the fg color... */
432 gc = tpd->renderReverseGC.gc;
434 valueMask = (unsigned long) 0;
435 if (tpd->renderReverseGC.foreground !=
436 tw->primitive.foreground) {
437 tpd->renderReverseGC.foreground = tw->primitive.foreground;
438 values.foreground = tw->primitive.foreground;
439 valueMask |= GCForeground;
442 (void) XChangeGC(XtDisplay(w), tpd->renderReverseGC.gc,
446 /* use the clear GC... */
447 gc = tpd->clearGC.gc;
450 if (isDebugFSet('t', 1)) {
454 /* Fill in the clear area so we can see what is going to
457 (void) XFillRectangle(XtDisplay(w),
460 chunkStartColumn * tpd->cellWidth + tpd->offsetX,
461 startRow * tpd->cellHeight + tpd->offsetY,
462 chunkWidth * tpd->cellWidth,
464 (void) XSync(XtDisplay(w), False);
465 (void) shortSleep(100000);
467 (void) XFillRectangle(XtDisplay(w),
469 XtWindow(w), /* Drawable */
471 chunkStartColumn * tpd->cellWidth + tpd->offsetX,
473 startRow * tpd->cellHeight + tpd->offsetY,
475 chunkWidth * tpd->cellWidth,
477 tpd->cellHeight); /* height */
478 chunkStartColumn += chunkWidth;
481 DebugF('t', 0, fprintf(stderr, ">>_DtTermPrimRefreshTextWc() finished\n"));
485 /**************************************************************************
487 * _DtTermPrimExposeText(): expose (refresh) the text in rectangular area
490 * Widget w: widget to expose
491 * int x: starting x pixel in window
492 * int y: starting y pixel in window
493 * int width: width in pixels
494 * int height: height in pixels
495 * Boolean isExposeEvent: true, deal with copyarea / expose overlap
501 * This function will redisplay the text in a rectangular exposure
502 * area. The x, y, width, and height are in absolute pixels. The
503 * internal x and y offsets will be accounted for, and the minimum
504 * number of characters will be displayed. The algorithm has been
505 * tuned (somewhat) and no longer exposes an extra character at the
506 * end of the refresh lines and an extra line at the bottom of the
507 * refresh area. This can be verified by using the 't' and 'e'
512 _DtTermPrimExposeTextMb(Widget w, int x, int y, int width, int height,
513 Boolean isExposeEvent)
515 struct termData *tpd = ((DtTermPrimitiveWidget) w)->term.tpd;
517 DebugF('e', 0, fprintf(stderr, ">>exposeText() starting\n"));
518 DebugF('e', 0, fprintf(stderr,
519 ">>exposeText() startX=%d startY=%d width=%d height=%d\n",
520 x, y, width, height));
521 DebugF('e', 0, fprintf(stderr,
522 ">> offsetX=%d offsetY=%d cellHeight=%d cellWidth=%d\n",
523 tpd->offsetX, tpd->offsetY, tpd->cellHeight, tpd->cellWidth));
525 /* The following "hack" takes care of the problem of an exposure event
526 * from the server and a copy area from the client crossing. The
527 * combination of these two events can cause a race condition which
528 * manifests itself by leaving a hole in the terminal window. What
531 * A window is partially obscured. The terminal emulator does a copy
532 * area (scroll) which includes part of obscured area. Before the
533 * server processes the copy area, the window is unobscured, and the
534 * server sends an exposure event back to the client.
536 * - The window is partially obscured.
538 * - The terminal emulator does a copy area (scroll) which includes a
539 * portion of the obscured area. Normally, the server will generate
540 * a graphics exposure event for the obscured portion that it can't
541 * copy which will allow the terminal emulator to update the area.
543 * - Before the server receives the copy area request, the server
544 * unobscures the window and sends an exposure event for the exposed
545 * area. (This is where the hack comes into play and refreshes the
546 * scrolled portion of this area (and possibly some extra space as
549 * - The server processes the copy area. Since the area in question is
550 * no longer obscured, the server will copy blank space and not
551 * generate a graphics exposure event.
553 * - The terminal emulator processes the exposure event and refreshes
554 * the exposed area. (This is the hack extends the exposure to cover
557 * - You now have a blank chunk of the terminal window where the
558 * obscured area was scrolled (without the hack).
560 * Our fix is similar to the one used in xterm. The Motif text widget
561 * uses a more brute force method and simply extends the exposure event
562 * to the full height (or width) of the screen in the direction of the
565 if (isExposeEvent && tpd->scrollInProgress) {
571 bothX1 = MAX(tpd->scrollSrcX, x);
572 bothY1 = MAX(tpd->scrollSrcY, y);
573 bothX2 = MIN(tpd->scrollSrcX + tpd->scrollWidth, x + width - 1);
574 bothY2 = MIN(tpd->scrollSrcY + tpd->scrollHeight, y + height - 1);
576 if ((bothX2 > bothX1) && (bothY2 > bothY1)) {
577 (void) _DtTermPrimRefreshTextWc(w,
578 (x - tpd->offsetX + tpd->scrollDestX - tpd->scrollSrcX) /
580 (y - tpd->offsetY + tpd->scrollDestY - tpd->scrollSrcY) /
582 (x + width - 1 - tpd->offsetX + tpd->scrollDestX -
583 tpd->scrollSrcX) / tpd->cellWidth,
584 (y + height - 1 - tpd->offsetY + tpd->scrollDestY -
585 tpd->scrollSrcY) / tpd->cellHeight);
589 /* render the text... */
590 DebugF('t', 0, fprintf(stderr, ">>exposeText() calling _DtTermPrimRefreshTextWc()\n"));
591 (void) _DtTermPrimRefreshTextWc(w, (x - tpd->offsetX) / tpd->cellWidth,
592 (y - tpd->offsetY) / tpd->cellHeight,
593 (x + width - 1 - tpd->offsetX) / tpd->cellWidth,
594 (y + height - 1 - tpd->offsetY) / tpd->cellHeight);
596 DebugF('e', 0, fprintf(stderr, ">>exposeText() finished\n"));
600 DoInsertWc(Widget w, wchar_t *wcBuffer, int wcBufferLen, Boolean *wrapped)
602 DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
603 struct termData *tpd = tw->term.tpd;
604 TermBuffer tBuffer = tpd->termBuffer;
606 wchar_t *returnChars;
610 ** before we insert any text, we need to insure that the cursor is on
611 ** a valid buffer row...
613 if (tpd->topRow + tpd->cursorRow >= tpd->lastUsedRow)
615 (void) _DtTermPrimFillScreenGap(w);
618 /* insert the text... */
619 returnChars = (wchar_t *) XtMalloc(BUFSIZ * sizeof (wchar_t));
620 newWidth = _DtTermPrimBufferInsertWc(tBuffer, /* TermBuffer */
621 tpd->topRow + tpd->cursorRow, /* row */
622 tpd->cursorColumn, /* column */
623 wcBuffer, /* newChars */
624 wcBufferLen, /* numChars */
625 tpd->insertCharMode != DtTERM_INSERT_CHAR_OFF, /* insert flag */
626 &returnChars, /* return char ptr */
627 &returnCount); /* return count ptr */
629 if ((tpd->insertCharMode != DtTERM_INSERT_CHAR_ON_WRAP) || (returnCount <= 0)) {
630 (void) XtFree((char *) returnChars);
634 /* we are in insert char mode with wrap and we wrapped text off of
639 /* wrap the inserted characters into the following line... */
640 if (tpd->topRow + tpd->cursorRow + 1 >= tpd->lastUsedRow) {
641 /* fake cursorRow... */
642 (void) tpd->cursorRow++;
643 (void) _DtTermPrimFillScreenGap(w);
644 (void) tpd->cursorRow--;
648 ** Copy the returned characters to a temporary buffer so we don't have to
649 ** worry about _DtTermPrimBufferInsertWc tromping over its overflow buffer...
651 wcBufferLen = returnCount;
652 wcBuffer = (wchar_t *)XtMalloc(wcBufferLen);
653 (void) memcpy(wcBuffer, returnChars, wcBufferLen * sizeof(wchar_t));
656 ** insert the text into the next line...
658 newWidth = _DtTermPrimBufferInsertWc(tBuffer, /* TermBuffer */
659 tpd->topRow + tpd->cursorRow + 1, /* row */
661 wcBuffer, /* newChars */
662 wcBufferLen, /* numChars */
663 tpd->insertCharMode != DtTERM_INSERT_CHAR_OFF, /* insert flag */
664 &returnChars, /* return char ptr */
665 &returnCount); /* return count ptr */
666 (void) XtFree((char *) wcBuffer);
667 (void) XtFree((char *) returnChars);
672 ** Insert the supplied text into the TermBuffer, and return a count of the
673 ** number of characters actually inserted.
676 _DtTermPrimInsertTextWc
679 wchar_t *wcBuffer, /* buffer of wide chars */
680 int wcBufLen /* # of wide chars in the buffer */
683 DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
684 struct termData *tpd = tw->term.tpd;
685 TermBuffer tBuffer = tpd->termBuffer;
691 short insertCharCount;
692 short insertCharWidth; /* column width of characters to insert */
695 Boolean needToRender = False;
696 Boolean wrapped = False;
698 /* turn off the cursor... */
699 if (CURSORoff != tpd->cursorState) {
700 (void) _DtTermPrimCursorOff(w);
703 /* we support two different types of autowrap. The HP style one is where
704 * you display the character and then wrap if you are at the end of the
705 * line. The ANSI style one is where you insert the character at the end
706 * of the line and don't autowrap until you try to insert another
710 renderStartX = tpd->cursorColumn;
711 renderEndX = tpd->cursorColumn;
712 insertStartX = tpd->cursorColumn;
716 for (i = 0; (i < wcBufLen) && tpd->ptyInputId; i++) {
717 thisCharWidth = MAX(1, wcwidth(wcBuffer[i]));
719 /* the following code performs two functions. If we are in
720 * autowrap, it performs a sanity check on the insert position.
721 * if we are not in autowrap, it will insure that characters
722 * inserted after the last position will replace the last
725 if (((tpd->cursorColumn + thisCharWidth) > tw->term.columns) &&
726 !(tpd->autoWrapRight && !tpd->wrapRightAfterInsert)) {
727 /* blow away the previous character...
729 tpd->cursorColumn = tw->term.columns - thisCharWidth;
730 renderStartX = MIN(renderStartX, tpd->cursorColumn);
731 tpd->wrapState = WRAPpastRightMargin;
734 /* for emulations that wrap after inserting the character, we
735 * will insert the character and then check for wrap...
737 if (tpd->wrapRightAfterInsert) {
738 if (insertCharCount == 0) {
742 (void) insertCharCount++;
743 insertCharWidth += thisCharWidth;
746 if (((tpd->cursorColumn + insertCharWidth +
747 (tpd->wrapRightAfterInsert ? 0: thisCharWidth)) >
749 ((tpd->cursorColumn + insertCharWidth +
750 (tpd->wrapRightAfterInsert ? 0 : (thisCharWidth - 1))) ==
751 tpd->rightMargin + 1)) {
752 if (tpd->autoWrapRight) {
753 /* perform an auto wrap...
755 /* we need to insert any pending characters, and
758 if (insertCharCount) {
759 newWidth = DoInsertWc(w, &wcBuffer[insertStartX],
760 insertCharCount, &wrapped);
761 tpd->cursorColumn += insertCharWidth;
763 if (tpd->insertCharMode == DtTERM_INSERT_CHAR_OFF) {
764 renderEndX = MAX(renderEndX, tpd->cursorColumn);
766 renderEndX = newWidth;
771 DebugF('t', 0, fprintf(stderr,
772 ">>termInsertText() calling[2] _DtTermPrimRefreshTextWc()\n"));
773 (void) _DtTermPrimRefreshTextWc(w, renderStartX, tpd->cursorRow,
774 wrapped ? tw->term.columns : MAX(renderEndX, 0),
776 if (wrapped && (tpd->cursorRow + 1 < tw->term.rows)) {
777 (void) _DtTermPrimRefreshTextWc(w, 0, tpd->cursorRow + 1,
778 renderEndX, tpd->cursorRow + 1);
781 needToRender = False;
783 tpd->cursorColumn = tpd->leftMargin;
784 tpd->wrapState = WRAPbetweenMargins;
787 _DtTermPrimBufferSetLineWrapFlag(tBuffer,
788 tpd->topRow + tpd->cursorRow,
791 if (tpd->cursorRow == tpd->scrollLockBottomRow) {
792 /* scroll at the bottom of the lock area... */
793 (void) _DtTermPrimScrollText(w, 1);
794 (void) _DtTermPrimFillScreenGap(w);
795 } else if (++tpd->cursorRow >= tw->term.rows) {
796 /* we are at the bottom row of the locked region.
797 * Wrap to the beginning of this line...
799 tpd->cursorRow = tw->term.rows - 1;
801 /* we are not at the bottom row. We already have
802 * wrapped down one line...
806 renderStartX = tpd->cursorColumn;
808 if (tpd->scroll.nojump.pendingScroll) {
809 /* If we wrapped the screen, bail out now and we
810 * will take care of this character when we
811 * finish the scroll. If we are in wrap after,
812 * then we need to skip past this character so
813 * that it doesn't get processed twice...
815 if (tpd->wrapRightAfterInsert)
820 /* overwrite the last character(s) on the line... */
821 if (insertCharCount > 0) {
822 newWidth = DoInsertWc(w, &wcBuffer[insertStartX],
823 insertCharCount, &wrapped);
824 tpd->cursorColumn += insertCharWidth;
826 if (tpd->insertCharMode == DtTERM_INSERT_CHAR_OFF) {
827 renderEndX = MAX(renderEndX, tpd->cursorColumn);
829 renderEndX = newWidth;
834 if (tpd->cursorColumn == tpd->rightMargin + 1)
835 tpd->cursorColumn = tpd->rightMargin;
837 tpd->cursorColumn = tw->term.columns - 1;
841 /* for emulations that wrap before inserting the character, we
842 * will insert the character and then check for wrap...
844 if (!tpd->wrapRightAfterInsert) {
845 /* before we insert any text, we need to insure that the
846 * cursor is on a valid buffer row...
848 if (insertCharCount == 0) {
852 (void) insertCharCount++;
853 insertCharWidth += thisCharWidth;
856 /* insert and render any remaining text... */
857 if (insertCharCount > 0) {
859 ** The following code performs two functions. If we are in
860 ** autowrap, it performs a sanity check on the insert position.
861 ** if we are not in autowrap, it will insure that characters
862 ** inserted after the last position will replace the last
866 ** This is only required in the case that we are trying to
867 ** overwrite the last character on the line with a two column
870 if (insertCharCount == 1 &&
871 thisCharWidth == 2 &&
872 ((tpd->cursorColumn + thisCharWidth) > tw->term.columns) &&
873 !(tpd->autoWrapRight && !tpd->wrapRightAfterInsert))
876 ** blow away the previous character...
878 tpd->cursorColumn = tw->term.columns - thisCharWidth;
879 renderStartX = MIN(renderStartX, tpd->cursorColumn);
880 tpd->wrapState = WRAPpastRightMargin;
882 newWidth = DoInsertWc(w, &wcBuffer[insertStartX],
883 insertCharCount, &wrapped);
884 tpd->cursorColumn += insertCharWidth;
886 if (tpd->insertCharMode == DtTERM_INSERT_CHAR_OFF) {
887 renderEndX = MAX(renderEndX, tpd->cursorColumn);
889 renderEndX = newWidth;
894 renderEndX = MAX(renderEndX, tpd->cursorColumn);
895 DebugF('t', 0, fprintf(stderr,
896 ">>termInsertText() calling _DtTermPrimRefreshTextWc()\n"));
897 (void) _DtTermPrimRefreshTextWc(w, renderStartX - 1, tpd->cursorRow,
898 wrapped ? tw->term.columns : MAX(renderEndX + 1, 0),
900 if (wrapped && (tpd->cursorRow + 1 < tw->term.rows)) {
901 (void) _DtTermPrimRefreshTextWc(w, 0, tpd->cursorRow + 1,
902 renderEndX + 1, tpd->cursorRow + 1);
905 needToRender = False;