"Fossies" - the Fresh Open Source Software Archive 
Member "xterm-379/util.c" (4 Jan 2023, 144274 Bytes) of package /linux/misc/xterm-379.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "util.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
377_vs_379.
1 /* $XTermId: util.c,v 1.914 2023/01/04 09:21:31 tom Exp $ */
2
3 /*
4 * Copyright 1999-2022,2023 by Thomas E. Dickey
5 *
6 * All Rights Reserved
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * Except as contained in this notice, the name(s) of the above copyright
28 * holders shall not be used in advertising or otherwise to promote the
29 * sale, use or other dealings in this Software without prior written
30 * authorization.
31 *
32 *
33 * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
34 *
35 * All Rights Reserved
36 *
37 * Permission to use, copy, modify, and distribute this software and its
38 * documentation for any purpose and without fee is hereby granted,
39 * provided that the above copyright notice appear in all copies and that
40 * both that copyright notice and this permission notice appear in
41 * supporting documentation, and that the name of Digital Equipment
42 * Corporation not be used in advertising or publicity pertaining to
43 * distribution of the software without specific, written prior permission.
44 *
45 *
46 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
47 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
48 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
49 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
50 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
51 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
52 * SOFTWARE.
53 */
54
55 /* util.c */
56
57 #include <xterm.h>
58
59 #include <data.h>
60 #include <error.h>
61 #include <menu.h>
62 #include <fontutils.h>
63 #include <xstrings.h>
64
65 #include <stdio.h>
66 #include <string.h>
67 #include <ctype.h>
68 #include <assert.h>
69
70 #if OPT_WIDE_CHARS
71 #if defined(HAVE_WCHAR_H) && defined(HAVE_WCWIDTH)
72 #include <wchar.h>
73 #endif
74 #include <wcwidth.h>
75 #endif
76
77 #ifdef HAVE_X11_EXTENSIONS_XINERAMA_H
78 #include <X11/extensions/Xinerama.h>
79 #endif /* HAVE_X11_EXTENSIONS_XINERAMA_H */
80
81 #include <graphics.h>
82
83 #define IncrementSavedLines(amount) \
84 if (screen->savedlines < screen->savelines) { \
85 if ((screen->savedlines += amount) > screen->savelines) \
86 screen->savedlines = screen->savelines; \
87 ScrollBarDrawThumb(xw, 1); \
88 }
89
90 static int handle_translated_exposure(XtermWidget xw,
91 int rect_x,
92 int rect_y,
93 int rect_width,
94 int rect_height);
95 static void ClearLeft(XtermWidget xw);
96 static void CopyWait(XtermWidget xw);
97 static void horizontal_copy_area(XtermWidget xw,
98 int firstchar,
99 int nchars,
100 int amount);
101 static void vertical_copy_area(XtermWidget xw,
102 int firstline,
103 int nlines,
104 int amount,
105 int left,
106 int right);
107
108 #if OPT_WIDE_CHARS
109 unsigned first_widechar;
110 int (*my_wcwidth) (wchar_t);
111 #endif
112
113 #if OPT_WIDE_CHARS
114 /*
115 * We will modify the 'n' cells beginning at the current position.
116 * Some of those cells may be part of multi-column characters, including
117 * carryover from the left. Find the limits of the multi-column characters
118 * that we should fill with blanks, return true if filling is needed.
119 */
120 int
121 DamagedCells(TScreen *screen, unsigned n, int *klp, int *krp, int row, int col)
122 {
123 CLineData *ld = getLineData(screen, row);
124 int result = False;
125
126 assert(ld);
127 if (col < (int) ld->lineSize) {
128 int nn = (int) n;
129 int kl = col;
130 int kr = col + nn;
131
132 if (kr >= (int) ld->lineSize) {
133 nn = (ld->lineSize - col - 1);
134 kr = col + nn;
135 }
136
137 if (nn > 0) {
138 assert(kl < (int) ld->lineSize);
139 if (ld->charData[kl] == HIDDEN_CHAR) {
140 while (kl > 0) {
141 if (ld->charData[--kl] != HIDDEN_CHAR) {
142 break;
143 }
144 }
145 } else {
146 kl = col + 1;
147 }
148
149 assert(kr < (int) ld->lineSize);
150 if (ld->charData[kr] == HIDDEN_CHAR) {
151 while (kr < screen->max_col) {
152 assert((kr + 1) < (int) ld->lineSize);
153 if (ld->charData[++kr] != HIDDEN_CHAR) {
154 --kr;
155 break;
156 }
157 }
158 } else {
159 kr = col - 1;
160 }
161
162 if (klp)
163 *klp = kl;
164 if (krp)
165 *krp = kr;
166 result = (kr >= kl);
167 }
168 }
169
170 return result;
171 }
172
173 int
174 DamagedCurCells(TScreen *screen, unsigned n, int *klp, int *krp)
175 {
176 return DamagedCells(screen, n, klp, krp, screen->cur_row, screen->cur_col);
177 }
178 #endif /* OPT_WIDE_CHARS */
179
180 /*
181 * These routines are used for the jump scroll feature
182 */
183 void
184 FlushScroll(XtermWidget xw)
185 {
186 TScreen *screen = TScreenOf(xw);
187 int i;
188 int shift = INX2ROW(screen, 0);
189 int bot = screen->max_row - shift;
190 int refreshtop;
191 int refreshheight;
192 int scrolltop;
193 int scrollheight;
194 int left = ScrnLeftMargin(xw);
195 int right = ScrnRightMargin(xw);
196 Boolean full_lines = (Boolean) ((left == 0) && (right == screen->max_col));
197
198 if (screen->cursor_state)
199 HideCursor(xw);
200
201 TRACE(("FlushScroll %s-lines scroll:%d refresh %d\n",
202 full_lines ? "full" : "partial",
203 screen->scroll_amt,
204 screen->refresh_amt));
205
206 if (screen->scroll_amt > 0) {
207 /*
208 * Lines will be scrolled "up".
209 */
210 refreshheight = screen->refresh_amt;
211 scrollheight = screen->bot_marg - screen->top_marg - refreshheight + 1;
212 refreshtop = screen->bot_marg - refreshheight + 1 + shift;
213 i = screen->max_row - screen->scroll_amt + 1;
214 if (refreshtop > i) {
215 refreshtop = i;
216 }
217
218 /*
219 * If this is the normal (not alternate) screen, and the top margin is
220 * at the top of the screen, then we will shift full lines scrolled out
221 * of the scrolling region into the saved-lines.
222 */
223 if (screen->scrollWidget
224 && !screen->whichBuf
225 && full_lines
226 && screen->top_marg == 0) {
227 scrolltop = 0;
228 scrollheight += shift;
229 if (scrollheight > i)
230 scrollheight = i;
231 i = screen->bot_marg - bot;
232 if (i > 0) {
233 refreshheight -= i;
234 if (refreshheight < screen->scroll_amt) {
235 refreshheight = screen->scroll_amt;
236 }
237 }
238 IncrementSavedLines(screen->scroll_amt);
239 } else {
240 scrolltop = screen->top_marg + shift;
241 i = bot - (screen->bot_marg - screen->refresh_amt + screen->scroll_amt);
242 if (i > 0) {
243 if (bot < screen->bot_marg) {
244 refreshheight = screen->scroll_amt + i;
245 }
246 } else {
247 scrollheight += i;
248 refreshheight = screen->scroll_amt;
249 i = screen->top_marg + screen->scroll_amt - 1 - bot;
250 if (i > 0) {
251 refreshtop += i;
252 refreshheight -= i;
253 }
254 }
255 }
256 } else {
257 /*
258 * Lines will be scrolled "down".
259 */
260 refreshheight = -screen->refresh_amt;
261 scrollheight = screen->bot_marg - screen->top_marg - refreshheight + 1;
262 refreshtop = screen->top_marg + shift;
263 scrolltop = refreshtop + refreshheight;
264 i = screen->bot_marg - bot;
265 if (i > 0) {
266 scrollheight -= i;
267 }
268 i = screen->top_marg + refreshheight - 1 - bot;
269 if (i > 0) {
270 refreshheight -= i;
271 }
272 }
273
274 vertical_copy_area(xw,
275 scrolltop + screen->scroll_amt,
276 scrollheight,
277 screen->scroll_amt,
278 left,
279 right);
280 ScrollSelection(screen, -(screen->scroll_amt), False);
281 screen->scroll_amt = 0;
282 screen->refresh_amt = 0;
283
284 if (refreshheight > 0) {
285 ClearCurBackground(xw,
286 refreshtop,
287 left,
288 (unsigned) refreshheight,
289 (unsigned) (right + 1 - left),
290 (unsigned) FontWidth(screen));
291 ScrnRefresh(xw,
292 refreshtop,
293 0,
294 refreshheight,
295 MaxCols(screen),
296 False);
297 }
298 xtermTimedDbe(xw);
299 return;
300 }
301
302 /*
303 * Returns true if there are lines off-screen due to scrolling which should
304 * include the current line. If false, the line is visible and we should
305 * paint it now rather than waiting for the line to become visible.
306 */
307 static Bool
308 AddToRefresh(XtermWidget xw)
309 {
310 TScreen *screen = TScreenOf(xw);
311 int amount = screen->refresh_amt;
312 int row = screen->cur_row;
313 Bool result;
314
315 if (amount == 0) {
316 result = False;
317 } else if (amount > 0) {
318 int bottom;
319
320 if (row == (bottom = screen->bot_marg) - amount) {
321 screen->refresh_amt++;
322 result = True;
323 } else {
324 result = (row >= bottom - amount + 1 && row <= bottom);
325 }
326 } else {
327 int top;
328
329 amount = -amount;
330 if (row == (top = screen->top_marg) + amount) {
331 screen->refresh_amt--;
332 result = True;
333 } else {
334 result = (row <= top + amount - 1 && row >= top);
335 }
336 }
337
338 /*
339 * If this line is visible, and there are scrolled-off lines, flush out
340 * those which are now visible.
341 */
342 if (!result && screen->scroll_amt)
343 FlushScroll(xw);
344
345 return result;
346 }
347
348 /*
349 * Returns true if the current row is in the visible area (it should be for
350 * screen operations) and incidentally flush the scrolled-in lines which
351 * have newly become visible.
352 */
353 static Bool
354 AddToVisible(XtermWidget xw)
355 {
356 TScreen *screen = TScreenOf(xw);
357 Bool result = False;
358
359 if (INX2ROW(screen, screen->cur_row) <= LastRowNumber(screen)) {
360 if (!AddToRefresh(xw)) {
361 result = True;
362 }
363 }
364 return result;
365 }
366
367 /*
368 * If we're scrolling, leave the selection intact if possible.
369 * If it will bump into one of the extremes of the saved-lines, truncate that.
370 * If the selection is not entirely contained within the margins and not
371 * entirely outside the margins, clear it.
372 */
373 static void
374 adjustHiliteOnFwdScroll(XtermWidget xw, int amount, Bool all_lines)
375 {
376 TScreen *screen = TScreenOf(xw);
377 int lo_row = (all_lines
378 ? (screen->bot_marg - screen->savelines)
379 : screen->top_marg);
380 int hi_row = screen->bot_marg;
381 int left = ScrnLeftMargin(xw);
382 int right = ScrnRightMargin(xw);
383
384 TRACE2(("adjustSelection FWD %s by %d (%s)\n",
385 screen->whichBuf ? "alternate" : "normal",
386 amount,
387 all_lines ? "all" : "visible"));
388 TRACE2((" before highlite %d.%d .. %d.%d\n",
389 screen->startH.row,
390 screen->startH.col,
391 screen->endH.row,
392 screen->endH.col));
393 TRACE2((" margins %d..%d\n", screen->top_marg, screen->bot_marg));
394 TRACE2((" limits %d..%d\n", lo_row, hi_row));
395
396 if ((left > 0 || right < screen->max_col) &&
397 ((screen->startH.row >= lo_row &&
398 screen->startH.row - amount <= hi_row) ||
399 (screen->endH.row >= lo_row &&
400 screen->endH.row - amount <= hi_row))) {
401 /*
402 * This could be improved slightly by excluding the special case where
403 * the selection is on a single line outside left/right margins.
404 */
405 TRACE2(("deselect because selection overlaps with scrolled partial-line\n"));
406 ScrnDisownSelection(xw);
407 } else if (screen->startH.row >= lo_row
408 && screen->startH.row - amount < lo_row) {
409 /* truncate the selection because its start would move out of region */
410 if (lo_row + amount <= screen->endH.row) {
411 TRACE2(("truncate selection by changing start %d.%d to %d.%d\n",
412 screen->startH.row,
413 screen->startH.col,
414 lo_row + amount,
415 0));
416 screen->startH.row = lo_row + amount;
417 screen->startH.col = 0;
418 } else {
419 TRACE2(("deselect because %d.%d .. %d.%d shifted %d is outside margins %d..%d\n",
420 screen->startH.row,
421 screen->startH.col,
422 screen->endH.row,
423 screen->endH.col,
424 -amount,
425 lo_row,
426 hi_row));
427 ScrnDisownSelection(xw);
428 }
429 } else if (screen->startH.row <= hi_row && screen->endH.row > hi_row) {
430 TRACE2(("deselect because selection straddles top-margin\n"));
431 ScrnDisownSelection(xw);
432 } else if (screen->startH.row < lo_row && screen->endH.row > lo_row) {
433 TRACE2(("deselect because selection straddles bottom-margin\n"));
434 ScrnDisownSelection(xw);
435 }
436
437 TRACE2((" after highlite %d.%d .. %d.%d\n",
438 screen->startH.row,
439 screen->startH.col,
440 screen->endH.row,
441 screen->endH.col));
442 }
443
444 /*
445 * This is the same as adjustHiliteOnFwdScroll(), but reversed. In this case,
446 * only the visible lines are affected.
447 */
448 static void
449 adjustHiliteOnBakScroll(XtermWidget xw, int amount)
450 {
451 TScreen *screen = TScreenOf(xw);
452 int lo_row = screen->top_marg;
453 int hi_row = screen->bot_marg;
454
455 TRACE2(("adjustSelection BAK %s by %d (%s)\n",
456 screen->whichBuf ? "alternate" : "normal",
457 amount,
458 "visible"));
459 TRACE2((" before highlite %d.%d .. %d.%d\n",
460 screen->startH.row,
461 screen->startH.col,
462 screen->endH.row,
463 screen->endH.col));
464 TRACE2((" margins %d..%d\n", screen->top_marg, screen->bot_marg));
465
466 if (screen->endH.row >= hi_row
467 && screen->endH.row + amount > hi_row) {
468 /* truncate the selection because its start would move out of region */
469 if (hi_row - amount >= screen->startH.row) {
470 TRACE2(("truncate selection by changing start %d.%d to %d.%d\n",
471 screen->startH.row,
472 screen->startH.col,
473 hi_row - amount,
474 0));
475 screen->endH.row = hi_row - amount;
476 screen->endH.col = 0;
477 } else {
478 TRACE2(("deselect because %d.%d .. %d.%d shifted %d is outside margins %d..%d\n",
479 screen->startH.row,
480 screen->startH.col,
481 screen->endH.row,
482 screen->endH.col,
483 amount,
484 lo_row,
485 hi_row));
486 ScrnDisownSelection(xw);
487 }
488 } else if (screen->endH.row >= lo_row && screen->startH.row < lo_row) {
489 ScrnDisownSelection(xw);
490 } else if (screen->endH.row > hi_row && screen->startH.row > hi_row) {
491 ScrnDisownSelection(xw);
492 }
493
494 TRACE2((" after highlite %d.%d .. %d.%d\n",
495 screen->startH.row,
496 screen->startH.col,
497 screen->endH.row,
498 screen->endH.col));
499 }
500
501 /*
502 * Move cells in LineData's on the current screen to simulate scrolling by the
503 * given amount of lines.
504 */
505 static void
506 scrollInMargins(XtermWidget xw, int amount, int top)
507 {
508 TScreen *screen = TScreenOf(xw);
509 LineData *src;
510 LineData *dst;
511 int row;
512 int left = ScrnLeftMargin(xw);
513 int right = ScrnRightMargin(xw);
514 int length = right + 1 - left;
515
516 if_OPT_WIDE_CHARS(screen, {
517 if (amount != 0) {
518 for (row = top; row <= screen->bot_marg; ++row) {
519 LineData *ld;
520 if ((ld = getLineData(screen, row + amount)) != 0) {
521 if (left > 0) {
522 if (ld->charData[left] == HIDDEN_CHAR) {
523 Clear1Cell(ld, left - 1);
524 Clear1Cell(ld, left);
525 }
526 }
527 if (right + 1 < (int) ld->lineSize) {
528 if (ld->charData[right + 1] == HIDDEN_CHAR) {
529 Clear1Cell(ld, right);
530 Clear1Cell(ld, right + 1);
531 }
532 }
533 }
534 }
535 }
536 });
537
538 if (amount > 0) {
539 for (row = top; row <= screen->bot_marg - amount; ++row) {
540 if ((src = getLineData(screen, row + amount)) != 0
541 && (dst = getLineData(screen, row)) != 0) {
542 CopyCells(screen, src, dst, left, length, False);
543 }
544 }
545 while (row <= screen->bot_marg) {
546 ClearCells(xw, 0, (unsigned) length, row, left);
547 ++row;
548 }
549 } else if (amount < 0) {
550 for (row = screen->bot_marg; row >= top - amount; --row) {
551 if ((src = getLineData(screen, row + amount)) != 0
552 && (dst = getLineData(screen, row)) != 0) {
553 CopyCells(screen, src, dst, left, length, True);
554 }
555 }
556 while (row >= top) {
557 ClearCells(xw, 0, (unsigned) length, row, left);
558 --row;
559 }
560 }
561 }
562
563 #if OPT_WIDE_CHARS
564 /*
565 * If we're repainting a section of wide-characters that, e.g., ClearCells has
566 * repaired when finding double-cell characters, then we should account for
567 * that in the repaint.
568 */
569 static void
570 ScrnUpdate2(XtermWidget xw,
571 int toprow,
572 int leftcol,
573 int nrows,
574 int ncols,
575 Bool force)
576 {
577 if_OPT_WIDE_CHARS(TScreenOf(xw), {
578 if (leftcol + ncols <= TScreenOf(xw)->max_col)
579 ncols++;
580 if (leftcol > 0) {
581 leftcol--;
582 ncols++;
583 }
584 });
585 ScrnUpdate(xw, toprow, leftcol, nrows, ncols, force);
586 }
587 #else
588 #define ScrnUpdate2(xw, toprow, leftcol, nrows, ncols, force) \
589 ScrnUpdate(xw, toprow, leftcol, nrows, ncols, force)
590 #endif
591
592 /*
593 * scrolls the screen by amount lines, erases bottom, doesn't alter
594 * cursor position (i.e. cursor moves down amount relative to text).
595 * All done within the scrolling region, of course.
596 * requires: amount > 0
597 */
598 void
599 xtermScroll(XtermWidget xw, int amount)
600 {
601 TScreen *screen = TScreenOf(xw);
602 int i;
603 int refreshtop = 0;
604 int refreshheight;
605 Boolean save_wrap = screen->do_wrap;
606 int left = ScrnLeftMargin(xw);
607 int right = ScrnRightMargin(xw);
608 Boolean scroll_all_lines = (Boolean) (screen->scrollWidget
609 && !screen->whichBuf
610 && screen->top_marg == 0);
611 Boolean scroll_full_line = ((left == 0) && (right == screen->max_col));
612
613 TRACE(("xtermScroll count=%d (top %d, saved %d)\n", amount,
614 screen->topline, screen->savelines));
615
616 screen->cursor_busy += 1;
617 screen->cursor_moved = True;
618
619 if (screen->cursor_state)
620 HideCursor(xw);
621
622 i = screen->bot_marg - screen->top_marg + 1;
623 if (amount > i)
624 amount = i;
625
626 if (!scroll_full_line) {
627 refreshheight = 0;
628 } else
629 #if OPT_SCROLL_LOCK
630 if ((screen->allowScrollLock && screen->scroll_lock)
631 || (screen->autoScrollLock && screen->topline < 0)) {
632 refreshheight = 0;
633 screen->scroll_amt = 0;
634 screen->refresh_amt = 0;
635 if (--(screen->topline) < -screen->savelines) {
636 screen->topline = -screen->savelines;
637 screen->scroll_dirty = True;
638 }
639 if (++(screen->savedlines) > screen->savelines) {
640 screen->savedlines = screen->savelines;
641 }
642 } else
643 #endif
644 {
645 if (ScrnHaveSelection(screen))
646 adjustHiliteOnFwdScroll(xw, amount, scroll_all_lines);
647
648 if (screen->jumpscroll) {
649 if (screen->scroll_amt > 0) {
650 if (!screen->fastscroll) {
651 if (screen->refresh_amt + amount > i)
652 FlushScroll(xw);
653 }
654 screen->scroll_amt += amount;
655 screen->refresh_amt += amount;
656 } else {
657 if (!screen->fastscroll) {
658 if (screen->scroll_amt < 0)
659 FlushScroll(xw);
660 }
661 screen->scroll_amt = amount;
662 screen->refresh_amt = amount;
663 }
664 refreshheight = 0;
665 } else {
666 int scrolltop;
667 int scrollheight;
668 int shift;
669 int bot;
670
671 ScrollSelection(screen, -(amount), False);
672 if (amount == i) {
673 ClearScreen(xw);
674 goto done;
675 }
676
677 shift = INX2ROW(screen, 0);
678 bot = screen->max_row - shift;
679 scrollheight = i - amount;
680 refreshheight = amount;
681
682 if ((refreshtop = screen->bot_marg - refreshheight + 1 + shift) >
683 (i = screen->max_row - refreshheight + 1))
684 refreshtop = i;
685
686 if (scroll_all_lines) {
687 scrolltop = 0;
688 if ((scrollheight += shift) > i)
689 scrollheight = i;
690 IncrementSavedLines(amount);
691 } else {
692 scrolltop = screen->top_marg + shift;
693 if ((i = screen->bot_marg - bot) > 0) {
694 scrollheight -= i;
695 if ((i = screen->top_marg + amount - 1 - bot) >= 0) {
696 refreshtop += i;
697 refreshheight -= i;
698 }
699 }
700 }
701
702 if (screen->multiscroll && amount == 1 &&
703 screen->topline == 0 && screen->top_marg == 0 &&
704 screen->bot_marg == screen->max_row) {
705 if (screen->incopy < 0 && screen->scrolls == 0)
706 CopyWait(xw);
707 screen->scrolls++;
708 }
709
710 vertical_copy_area(xw,
711 scrolltop + amount,
712 scrollheight,
713 amount,
714 left,
715 right);
716
717 if (refreshheight > 0) {
718 ClearCurBackground(xw,
719 refreshtop,
720 left,
721 (unsigned) refreshheight,
722 (unsigned) (right + 1 - left),
723 (unsigned) FontWidth(screen));
724 if (refreshheight > shift)
725 refreshheight = shift;
726 }
727 }
728 }
729
730 if (amount > 0) {
731 if (left > 0 || right < screen->max_col) {
732 scrollInMargins(xw, amount, screen->top_marg);
733 ScrnUpdate2(xw,
734 screen->top_marg,
735 left,
736 screen->bot_marg + 1 - screen->top_marg,
737 right + 1 - left,
738 True);
739 } else if (scroll_all_lines) {
740 ScrnDeleteLine(xw,
741 screen->saveBuf_index,
742 screen->bot_marg + screen->savelines,
743 0,
744 (unsigned) amount);
745 } else {
746 ScrnDeleteLine(xw,
747 screen->visbuf,
748 screen->bot_marg,
749 screen->top_marg,
750 (unsigned) amount);
751 }
752 }
753
754 scroll_displayed_graphics(xw, amount);
755
756 if (refreshheight > 0) {
757 ScrnRefresh(xw,
758 refreshtop,
759 left,
760 refreshheight,
761 right + 1 - left,
762 False);
763 }
764
765 done:
766 screen->do_wrap = save_wrap;
767 screen->cursor_busy -= 1;
768 TRACE(("...xtermScroll count=%d (top %d, saved %d)\n", amount,
769 screen->topline, screen->savelines));
770 return;
771 }
772
773 /*
774 * This is from ISO 6429, not found in any of DEC's terminals.
775 */
776 void
777 xtermScrollLR(XtermWidget xw, int amount, Bool toLeft)
778 {
779 if (amount > 0) {
780 xtermColScroll(xw, amount, toLeft, ScrnLeftMargin(xw));
781 }
782 }
783
784 /*
785 * Implement DECBI/DECFI (back/forward column index)
786 */
787 void
788 xtermColIndex(XtermWidget xw, Bool toLeft)
789 {
790 TScreen *screen = TScreenOf(xw);
791
792 if (toLeft) {
793 if (ScrnIsColInMargins(screen, screen->cur_col)) {
794 if (screen->cur_col == ScrnLeftMargin(xw)) {
795 xtermColScroll(xw, 1, False, screen->cur_col);
796 } else {
797 CursorBack(xw, 1);
798 }
799 } else {
800 CursorBack(xw, 1);
801 }
802 } else {
803 if (ScrnIsColInMargins(screen, screen->cur_col)) {
804 if (screen->cur_col == ScrnRightMargin(xw)) {
805 xtermColScroll(xw, 1, True, ScrnLeftMargin(xw));
806 } else {
807 CursorForward(xw, 1);
808 }
809 } else {
810 CursorForward(xw, 1);
811 }
812 }
813 }
814
815 /*
816 * Implement DECDC/DECIC (delete/insert column)
817 */
818 void
819 xtermColScroll(XtermWidget xw, int amount, Bool toLeft, int at_col)
820 {
821 TScreen *screen = TScreenOf(xw);
822
823 if (amount > 0) {
824 int min_row;
825 int max_row;
826
827 if (ScrnHaveRowMargins(screen)) {
828 min_row = screen->top_marg;
829 max_row = screen->bot_marg;
830 } else {
831 min_row = 0;
832 max_row = screen->max_row;
833 }
834
835 if (screen->cur_row >= min_row
836 && screen->cur_row <= max_row
837 && screen->cur_col >= screen->lft_marg
838 && screen->cur_col <= screen->rgt_marg) {
839 int save_row = screen->cur_row;
840 int save_col = screen->cur_col;
841 int row;
842
843 screen->cur_col = at_col;
844 if (toLeft) {
845 for (row = min_row; row <= max_row; row++) {
846 screen->cur_row = row;
847 ScrnDeleteChar(xw, (unsigned) amount);
848 }
849 } else {
850 for (row = min_row; row <= max_row; row++) {
851 screen->cur_row = row;
852 ScrnInsertChar(xw, (unsigned) amount);
853 }
854 }
855 screen->cur_row = save_row;
856 screen->cur_col = save_col;
857 xtermRepaint(xw);
858 }
859 }
860 }
861
862 /*
863 * Reverse scrolls the screen by amount lines, erases top, doesn't alter
864 * cursor position (i.e. cursor moves up amount relative to text).
865 * All done within the scrolling region, of course.
866 * Requires: amount > 0
867 */
868 void
869 RevScroll(XtermWidget xw, int amount)
870 {
871 TScreen *screen = TScreenOf(xw);
872 int i = screen->bot_marg - screen->top_marg + 1;
873 int left = ScrnLeftMargin(xw);
874 int right = ScrnRightMargin(xw);
875 Boolean scroll_full_line = ((left == 0) && (right == screen->max_col));
876
877 TRACE(("RevScroll count=%d\n", amount));
878
879 screen->cursor_busy += 1;
880 screen->cursor_moved = True;
881
882 if (screen->cursor_state)
883 HideCursor(xw);
884
885 if (amount > i)
886 amount = i;
887
888 if (ScrnHaveSelection(screen))
889 adjustHiliteOnBakScroll(xw, amount);
890
891 if (!scroll_full_line) {
892 ;
893 } else if (screen->jumpscroll) {
894 if (screen->scroll_amt < 0) {
895 if (-screen->refresh_amt + amount > i)
896 FlushScroll(xw);
897 screen->scroll_amt -= amount;
898 screen->refresh_amt -= amount;
899 } else {
900 if (screen->scroll_amt > 0)
901 FlushScroll(xw);
902 screen->scroll_amt = -amount;
903 screen->refresh_amt = -amount;
904 }
905 } else {
906 int shift = INX2ROW(screen, 0);
907 int bot = screen->max_row - shift;
908 int refreshheight = amount;
909 int refreshtop = screen->top_marg + shift;
910 int scrollheight = (screen->bot_marg
911 - screen->top_marg - refreshheight + 1);
912 int scrolltop = refreshtop + refreshheight;
913
914 if ((i = screen->bot_marg - bot) > 0)
915 scrollheight -= i;
916 if ((i = screen->top_marg + refreshheight - 1 - bot) > 0)
917 refreshheight -= i;
918
919 if (screen->multiscroll && amount == 1 &&
920 screen->topline == 0 && screen->top_marg == 0 &&
921 screen->bot_marg == screen->max_row) {
922 if (screen->incopy < 0 && screen->scrolls == 0)
923 CopyWait(xw);
924 screen->scrolls++;
925 }
926
927 vertical_copy_area(xw,
928 scrolltop - amount,
929 scrollheight,
930 -amount,
931 left,
932 right);
933
934 if (refreshheight > 0) {
935 ClearCurBackground(xw,
936 refreshtop,
937 left,
938 (unsigned) refreshheight,
939 (unsigned) (right + 1 - left),
940 (unsigned) FontWidth(screen));
941 }
942 }
943 if (amount > 0) {
944 if (left > 0 || right < screen->max_col) {
945 scrollInMargins(xw, -amount, screen->top_marg);
946 ScrnUpdate2(xw,
947 screen->top_marg,
948 left,
949 screen->bot_marg + 1 - screen->top_marg,
950 right + 1 - left,
951 True);
952 } else {
953 ScrnInsertLine(xw,
954 screen->visbuf,
955 screen->bot_marg,
956 screen->top_marg,
957 (unsigned) amount);
958 }
959 }
960 screen->cursor_busy -= 1;
961 return;
962 }
963
964 #if OPT_ZICONBEEP
965 void
966 initZIconBeep(void)
967 {
968 if (resource.zIconBeep > 100 || resource.zIconBeep < -100) {
969 resource.zIconBeep = 0; /* was 100, but I prefer to defaulting off. */
970 xtermWarning("a number between -100 and 100 is required for zIconBeep. 0 used by default\n");
971 }
972 }
973
974 static char *
975 getIconName(void)
976 {
977 static char *icon_name;
978 static Arg args[] =
979 {
980 {XtNiconName, (XtArgVal) & icon_name}
981 };
982
983 icon_name = NULL;
984 XtGetValues(toplevel, args, XtNumber(args));
985 return icon_name;
986 }
987
988 static void
989 setZIconBeep(XtermWidget xw)
990 {
991 TScreen *screen = TScreenOf(xw);
992
993 /* Flag icon name with "***" on window output when iconified.
994 */
995 if (resource.zIconBeep && mapstate == IsUnmapped && !screen->zIconBeep_flagged) {
996 char *icon_name = getIconName();
997 if (icon_name != NULL) {
998 screen->zIconBeep_flagged = True;
999 ChangeIconName(xw, icon_name);
1000 }
1001 xtermBell(xw, XkbBI_Info, 0);
1002 }
1003 mapstate = -1;
1004 }
1005
1006 /*
1007 * If warning should be given then give it
1008 */
1009 Boolean
1010 showZIconBeep(XtermWidget xw, char *name)
1011 {
1012 Boolean code = False;
1013
1014 if (resource.zIconBeep && TScreenOf(xw)->zIconBeep_flagged) {
1015 char *format = resource.zIconFormat;
1016 char *newname = malloc(strlen(name) + strlen(format) + 2);
1017 if (!newname) {
1018 xtermWarning("malloc failed in showZIconBeep\n");
1019 } else {
1020 char *marker = strstr(format, "%s");
1021 char *result = newname;
1022 if (marker != 0) {
1023 size_t skip = (size_t) (marker - format);
1024 if (skip) {
1025 strncpy(result, format, skip);
1026 result += skip;
1027 }
1028 strcpy(result, name);
1029 strcat(result, marker + 2);
1030 } else {
1031 strcpy(result, format);
1032 strcat(result, name);
1033 }
1034 ChangeGroup(xw, XtNiconName, newname);
1035 free(newname);
1036 }
1037 code = True;
1038 }
1039 return code;
1040 }
1041
1042 /*
1043 * Restore the icon name, resetting the state for zIconBeep.
1044 */
1045 void
1046 resetZIconBeep(XtermWidget xw)
1047 {
1048 TScreen *screen = TScreenOf(xw);
1049
1050 if (screen->zIconBeep_flagged) {
1051 char *icon_name = getIconName();
1052 screen->zIconBeep_flagged = False;
1053 if (icon_name != NULL) {
1054 char *buf = malloc(strlen(icon_name) + 1);
1055 if (buf == NULL) {
1056 screen->zIconBeep_flagged = True;
1057 } else {
1058 char *format = resource.zIconFormat;
1059 char *marker = strstr(format, "%s");
1060 Boolean found = False;
1061
1062 if (marker != 0) {
1063 if (marker == format
1064 || !strncmp(icon_name, format, (size_t) (marker - format))) {
1065 found = True;
1066 strcpy(buf, icon_name + (marker - format));
1067 marker += 2;
1068 if (*marker != '\0') {
1069 size_t len_m = strlen(marker);
1070 size_t len_b = strlen(buf);
1071 if (len_m < len_b
1072 && !strcmp(buf + len_b - len_m, marker)) {
1073 buf[len_b - len_m] = '\0';
1074 }
1075 }
1076 }
1077 } else if (!strncmp(icon_name, format, strlen(format))) {
1078 strcpy(buf, icon_name + strlen(format));
1079 found = True;
1080 }
1081 if (found)
1082 ChangeIconName(xw, buf);
1083 free(buf);
1084 }
1085 }
1086 }
1087 }
1088 #else
1089 #define setZIconBeep(xw) /* nothing */
1090 #endif /* OPT_ZICONBEEP */
1091
1092 /*
1093 * write a string str of length len onto the screen at
1094 * the current cursor position. update cursor position.
1095 */
1096 void
1097 WriteText(XtermWidget xw, IChar *str, Cardinal len)
1098 {
1099 TScreen *screen = TScreenOf(xw);
1100 XTermDraw params;
1101 CLineData *ld = 0;
1102 unsigned attr_flags = xw->flags;
1103 CellColor fg_bg = xtermColorPair(xw);
1104 unsigned cells = visual_width(str, len);
1105 GC currentGC;
1106
1107 TRACE(("WriteText %d (%2d,%2d) %3d:%s\n",
1108 screen->topline,
1109 screen->cur_row,
1110 screen->cur_col,
1111 len, visibleIChars(str, len)));
1112
1113 if (cells + (unsigned) screen->cur_col > (unsigned) MaxCols(screen)) {
1114 cells = (unsigned) (MaxCols(screen) - screen->cur_col);
1115 }
1116
1117 if (screen->cur_row <= screen->max_row
1118 && ScrnHaveSelection(screen)
1119 && ScrnIsRowInSelection(screen, INX2ROW(screen, screen->cur_row))) {
1120 ScrnDisownSelection(xw);
1121 }
1122 #if OPT_ISO_COLORS
1123 /* if colorBDMode is set, and enabled */
1124 if (screen->colorBDMode &&
1125 screen->boldColors &&
1126 !hasDirectFG(attr_flags) &&
1127 /* and bold foreground color on bold background color */
1128 GetCellColorFG(fg_bg) > COLOR_7 &&
1129 GetCellColorFG(fg_bg) < MIN_ANSI_COLORS &&
1130 /* and both colors are the same */
1131 GetCellColorFG(fg_bg) == GetCellColorBG(fg_bg))
1132 /* clear BOLD flag, else it will be colorBD on bold background color */
1133 UIntClr(attr_flags, BOLD);
1134 #endif
1135
1136 /* if we are in insert-mode, reserve space for the new cells */
1137 if (attr_flags & INSERT) {
1138 InsertChar(xw, cells);
1139 }
1140
1141 if (AddToVisible(xw)
1142 && ((ld = getLineData(screen, screen->cur_row))) != 0) {
1143 unsigned test;
1144
1145 if (screen->cursor_state)
1146 HideCursor(xw);
1147
1148 /*
1149 * If we overwrite part of a multi-column character, fill the rest
1150 * of it with blanks.
1151 */
1152 if_OPT_WIDE_CHARS(screen, {
1153 int kl;
1154 int kr;
1155 if (DamagedCurCells(screen, cells, &kl, &kr))
1156 ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1));
1157 });
1158
1159 if (attr_flags & INVISIBLE) {
1160 Cardinal n;
1161 for (n = 0; n < cells; ++n)
1162 str[n] = ' ';
1163 }
1164
1165 TRACE(("WriteText calling drawXtermText (%d) (%d,%d)\n",
1166 LineCharSet(screen, ld),
1167 screen->cur_row,
1168 screen->cur_col));
1169
1170 test = attr_flags;
1171 #if OPT_ISO_COLORS
1172 {
1173 int fg;
1174 if (screen->colorAttrMode) {
1175 fg = MapToColorMode(xw->cur_foreground, screen, attr_flags);
1176 } else {
1177 fg = xw->cur_foreground;
1178 }
1179 checkVeryBoldColors(test, fg);
1180 }
1181 #endif
1182
1183 /* make sure that the correct GC is current */
1184 currentGC = updatedXtermGC(xw, attr_flags, fg_bg, False);
1185
1186 /* *INDENT-EQLS* */
1187 params.xw = xw;
1188 params.attr_flags = (test & DRAWX_MASK);
1189 params.draw_flags = 0;
1190 params.this_chrset = LineCharSet(screen, ld);
1191 params.real_chrset = CSET_SWL;
1192 params.on_wide = 0;
1193
1194 drawXtermText(¶ms,
1195 currentGC,
1196 LineCursorX(screen, ld, screen->cur_col),
1197 CursorY(screen, screen->cur_row),
1198 str, len);
1199
1200 resetXtermGC(xw, attr_flags, False);
1201 }
1202
1203 ScrnWriteText(xw, str, attr_flags, fg_bg, len);
1204 CursorForward(xw, (int) cells);
1205
1206 if (screen->cur_row <= screen->max_row) {
1207 setZIconBeep(xw);
1208 }
1209 return;
1210 }
1211
1212 /*
1213 * If cursor not in scrolling region, returns. Else,
1214 * inserts n blank lines at the cursor's position. Lines above the
1215 * bottom margin are lost.
1216 */
1217 void
1218 InsertLine(XtermWidget xw, int n)
1219 {
1220 TScreen *screen = TScreenOf(xw);
1221 int i;
1222 int left = ScrnLeftMargin(xw);
1223 int right = ScrnRightMargin(xw);
1224 Boolean scroll_full_line = ((left == 0) && (right == screen->max_col));
1225
1226 if (!ScrnIsRowInMargins(screen, screen->cur_row)
1227 || screen->cur_col < left
1228 || screen->cur_col > right)
1229 return;
1230
1231 TRACE(("InsertLine count=%d\n", n));
1232
1233 set_cur_col(screen, ScrnLeftMargin(xw));
1234 if (screen->cursor_state)
1235 HideCursor(xw);
1236
1237 if (ScrnHaveSelection(screen)
1238 && ScrnAreRowsInSelection(screen,
1239 INX2ROW(screen, screen->top_marg),
1240 INX2ROW(screen, screen->cur_row - 1))
1241 && ScrnAreRowsInSelection(screen,
1242 INX2ROW(screen, screen->cur_row),
1243 INX2ROW(screen, screen->bot_marg))) {
1244 ScrnDisownSelection(xw);
1245 }
1246
1247 ResetWrap(screen);
1248 if (n > (i = screen->bot_marg - screen->cur_row + 1))
1249 n = i;
1250 if (screen->jumpscroll && scroll_full_line) {
1251 if (screen->scroll_amt <= 0 &&
1252 screen->cur_row <= -screen->refresh_amt) {
1253 if (-screen->refresh_amt + n > MaxRows(screen))
1254 FlushScroll(xw);
1255 screen->scroll_amt -= n;
1256 screen->refresh_amt -= n;
1257 } else {
1258 if (screen->scroll_amt)
1259 FlushScroll(xw);
1260 }
1261 }
1262 if (!screen->scroll_amt && scroll_full_line) {
1263 int shift = INX2ROW(screen, 0);
1264 int bot = screen->max_row - shift;
1265 int refreshheight = n;
1266 int refreshtop = screen->cur_row + shift;
1267 int scrolltop = refreshtop + refreshheight;
1268 int scrollheight = (screen->bot_marg
1269 - screen->cur_row - refreshheight + 1);
1270
1271 if ((i = screen->bot_marg - bot) > 0)
1272 scrollheight -= i;
1273 if ((i = screen->cur_row + refreshheight - 1 - bot) > 0)
1274 refreshheight -= i;
1275 vertical_copy_area(xw, scrolltop - n, scrollheight, -n, left, right);
1276 if (refreshheight > 0) {
1277 ClearCurBackground(xw,
1278 refreshtop,
1279 left,
1280 (unsigned) refreshheight,
1281 (unsigned) (right + 1 - left),
1282 (unsigned) FontWidth(screen));
1283 }
1284 }
1285 if (n > 0) {
1286 if (scroll_full_line) {
1287 ScrnInsertLine(xw,
1288 screen->visbuf,
1289 screen->bot_marg,
1290 screen->cur_row,
1291 (unsigned) n);
1292 } else {
1293 scrollInMargins(xw, -n, screen->cur_row);
1294 ScrnUpdate2(xw,
1295 screen->cur_row,
1296 left,
1297 screen->bot_marg + 1 - screen->cur_row,
1298 right + 1 - left,
1299 True);
1300 }
1301 }
1302 }
1303
1304 /*
1305 * If cursor not in scrolling region, returns. Else, deletes n lines
1306 * at the cursor's position, lines added at bottom margin are blank.
1307 */
1308 void
1309 DeleteLine(XtermWidget xw, int n, Bool canSave)
1310 {
1311 TScreen *screen = TScreenOf(xw);
1312 int i;
1313 int left = ScrnLeftMargin(xw);
1314 int right = ScrnRightMargin(xw);
1315 Boolean scroll_all_lines = (Boolean) (screen->scrollWidget
1316 && !screen->whichBuf
1317 && screen->cur_row == 0);
1318 Boolean scroll_full_line = ((left == 0) && (right == screen->max_col));
1319
1320 if (!ScrnIsRowInMargins(screen, screen->cur_row) ||
1321 !ScrnIsColInMargins(screen, screen->cur_col))
1322 return;
1323
1324 TRACE(("DeleteLine count=%d\n", n));
1325
1326 set_cur_col(screen, ScrnLeftMargin(xw));
1327 if (screen->cursor_state)
1328 HideCursor(xw);
1329
1330 if (n > (i = screen->bot_marg - screen->cur_row + 1)) {
1331 n = i;
1332 }
1333 if (ScrnHaveSelection(screen)
1334 && ScrnAreRowsInSelection(screen,
1335 INX2ROW(screen, screen->cur_row),
1336 INX2ROW(screen, screen->cur_row + n - 1))) {
1337 ScrnDisownSelection(xw);
1338 }
1339
1340 ResetWrap(screen);
1341 if (screen->jumpscroll && scroll_full_line) {
1342 if (screen->scroll_amt >= 0 && screen->cur_row == screen->top_marg) {
1343 if (screen->refresh_amt + n > MaxRows(screen))
1344 FlushScroll(xw);
1345 if (canSave) {
1346 screen->scroll_amt += n;
1347 screen->refresh_amt += n;
1348 }
1349 } else {
1350 if (screen->scroll_amt)
1351 FlushScroll(xw);
1352 }
1353 }
1354
1355 /* adjust screen->buf */
1356 if (n > 0) {
1357 if (left > 0 || right < screen->max_col) {
1358 scrollInMargins(xw, n, screen->cur_row);
1359 } else if (canSave && scroll_all_lines) {
1360 ScrnDeleteLine(xw,
1361 screen->saveBuf_index,
1362 screen->bot_marg + screen->savelines,
1363 0,
1364 (unsigned) n);
1365 } else {
1366 ScrnDeleteLine(xw,
1367 screen->visbuf,
1368 screen->bot_marg,
1369 screen->cur_row,
1370 (unsigned) n);
1371 }
1372 }
1373
1374 /* repaint the screen, as needed */
1375 if (!scroll_full_line) {
1376 ScrnUpdate2(xw,
1377 screen->cur_row,
1378 left,
1379 screen->bot_marg + 1 - screen->cur_row,
1380 right + 1 - left,
1381 True);
1382 } else if (!screen->scroll_amt) {
1383 int shift = INX2ROW(screen, 0);
1384 int bot = screen->max_row - shift;
1385 int refreshtop;
1386 int refreshheight = n;
1387 int scrolltop;
1388 int scrollheight = i - n;
1389
1390 if ((refreshtop = screen->bot_marg - refreshheight + 1 + shift) >
1391 (i = screen->max_row - refreshheight + 1))
1392 refreshtop = i;
1393 if (canSave && scroll_all_lines) {
1394 scrolltop = 0;
1395 if ((scrollheight += shift) > i)
1396 scrollheight = i;
1397 IncrementSavedLines(n);
1398 } else {
1399 scrolltop = screen->cur_row + shift;
1400 if ((i = screen->bot_marg - bot) > 0) {
1401 scrollheight -= i;
1402 if ((i = screen->cur_row + n - 1 - bot) >= 0) {
1403 refreshheight -= i;
1404 }
1405 }
1406 }
1407 vertical_copy_area(xw, scrolltop + n, scrollheight, n, left, right);
1408 if (shift > 0 && refreshheight > 0) {
1409 int rows = refreshheight;
1410 if (rows > shift)
1411 rows = shift;
1412 ScrnUpdate(xw, refreshtop, 0, rows, MaxCols(screen), True);
1413 refreshtop += shift;
1414 refreshheight -= shift;
1415 }
1416 if (refreshheight > 0) {
1417 ClearCurBackground(xw,
1418 refreshtop,
1419 left,
1420 (unsigned) refreshheight,
1421 (unsigned) (right + 1 - left),
1422 (unsigned) FontWidth(screen));
1423 }
1424 }
1425 }
1426
1427 /*
1428 * Insert n blanks at the cursor's position, no wraparound
1429 */
1430 void
1431 InsertChar(XtermWidget xw, unsigned n)
1432 {
1433 TScreen *screen = TScreenOf(xw);
1434 CLineData *ld;
1435 unsigned limit;
1436 int row = INX2ROW(screen, screen->cur_row);
1437 int left = ScrnLeftMargin(xw);
1438 int right = ScrnRightMargin(xw);
1439
1440 if (screen->cursor_state)
1441 HideCursor(xw);
1442
1443 TRACE(("InsertChar count=%d\n", n));
1444
1445 if (ScrnHaveSelection(screen)
1446 && ScrnIsRowInSelection(screen, row)) {
1447 ScrnDisownSelection(xw);
1448 }
1449 ResetWrap(screen);
1450
1451 limit = (unsigned) (right + 1 - screen->cur_col);
1452
1453 if (n > limit)
1454 n = limit;
1455
1456 if (screen->cur_col < left || screen->cur_col > right) {
1457 n = 0;
1458 } else if (AddToVisible(xw)
1459 && (ld = getLineData(screen, screen->cur_row)) != 0) {
1460 int col = right + 1 - (int) n;
1461
1462 /*
1463 * If we shift part of a multi-column character, fill the rest
1464 * of it with blanks. Do similar repair for the text which will
1465 * be shifted into the right-margin.
1466 */
1467 if_OPT_WIDE_CHARS(screen, {
1468 int kl;
1469 int kr = screen->cur_col;
1470 if (DamagedCurCells(screen, n, &kl, (int *) 0) && kr > kl) {
1471 ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1));
1472 }
1473 kr = screen->max_col - (int) n + 1;
1474 if (DamagedCells(screen, n, &kl, (int *) 0,
1475 screen->cur_row,
1476 kr) && kr > kl) {
1477 ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1));
1478 }
1479 });
1480
1481 #if OPT_DEC_CHRSET
1482 if (CSET_DOUBLE(GetLineDblCS(ld))) {
1483 col = MaxCols(screen) / 2 - (int) n;
1484 }
1485 #endif
1486 /*
1487 * prevent InsertChar from shifting the end of a line over
1488 * if it is being appended to
1489 */
1490 if (non_blank_line(screen, screen->cur_row,
1491 screen->cur_col, MaxCols(screen))) {
1492 horizontal_copy_area(xw, screen->cur_col,
1493 col - screen->cur_col,
1494 (int) n);
1495 }
1496
1497 ClearCurBackground(xw,
1498 INX2ROW(screen, screen->cur_row),
1499 screen->cur_col,
1500 1U,
1501 n,
1502 (unsigned) LineFontWidth(screen, ld));
1503 }
1504 if (n != 0) {
1505 /* adjust screen->buf */
1506 ScrnInsertChar(xw, n);
1507 }
1508 }
1509
1510 /*
1511 * Deletes n chars at the cursor's position, no wraparound.
1512 */
1513 void
1514 DeleteChar(XtermWidget xw, unsigned n)
1515 {
1516 TScreen *screen = TScreenOf(xw);
1517 CLineData *ld;
1518 unsigned limit;
1519 int row = INX2ROW(screen, screen->cur_row);
1520 int right = ScrnRightMargin(xw);
1521
1522 if (screen->cursor_state)
1523 HideCursor(xw);
1524
1525 if (!ScrnIsColInMargins(screen, screen->cur_col))
1526 return;
1527
1528 TRACE(("DeleteChar count=%d\n", n));
1529
1530 if (ScrnHaveSelection(screen)
1531 && ScrnIsRowInSelection(screen, row)) {
1532 ScrnDisownSelection(xw);
1533 }
1534 ResetWrap(screen);
1535
1536 limit = (unsigned) (right + 1 - screen->cur_col);
1537
1538 if (n > limit)
1539 n = limit;
1540
1541 if (AddToVisible(xw)
1542 && (ld = getLineData(screen, screen->cur_row)) != 0) {
1543 int col = right + 1 - (int) n;
1544
1545 /*
1546 * If we delete part of a multi-column character, fill the rest
1547 * of it with blanks.
1548 */
1549 if_OPT_WIDE_CHARS(screen, {
1550 int kl;
1551 int kr;
1552 if (DamagedCurCells(screen, n, &kl, &kr))
1553 ClearInLine(xw, screen->cur_row, kl, (unsigned) (kr - kl + 1));
1554 });
1555
1556 #if OPT_DEC_CHRSET
1557 if (CSET_DOUBLE(GetLineDblCS(ld))) {
1558 col = MaxCols(screen) / 2 - (int) n;
1559 }
1560 #endif
1561 horizontal_copy_area(xw,
1562 (screen->cur_col + (int) n),
1563 col - screen->cur_col,
1564 -((int) n));
1565
1566 ClearCurBackground(xw,
1567 INX2ROW(screen, screen->cur_row),
1568 col,
1569 1U,
1570 n,
1571 (unsigned) LineFontWidth(screen, ld));
1572 }
1573 if (n != 0) {
1574 /* adjust screen->buf */
1575 ScrnDeleteChar(xw, n);
1576 }
1577 }
1578
1579 /*
1580 * Clear from cursor position to beginning of display, inclusive.
1581 */
1582 static void
1583 ClearAbove(XtermWidget xw)
1584 {
1585 TScreen *screen = TScreenOf(xw);
1586
1587 if (screen->protected_mode != OFF_PROTECT) {
1588 int row;
1589 unsigned len = (unsigned) MaxCols(screen);
1590
1591 assert(screen->max_col >= 0);
1592 for (row = 0; row < screen->cur_row; row++)
1593 ClearInLine(xw, row, 0, len);
1594 ClearInLine(xw, screen->cur_row, 0, (unsigned) screen->cur_col);
1595 } else {
1596 int top;
1597
1598 if (screen->cursor_state)
1599 HideCursor(xw);
1600 if ((top = INX2ROW(screen, 0)) <= screen->max_row) {
1601 int height;
1602
1603 if (screen->scroll_amt)
1604 FlushScroll(xw);
1605 if ((height = screen->cur_row + top) > screen->max_row)
1606 height = screen->max_row + 1;
1607 if ((height -= top) > 0) {
1608 chararea_clear_displayed_graphics(screen,
1609 0,
1610 top,
1611 MaxCols(screen),
1612 height);
1613
1614 ClearCurBackground(xw,
1615 top,
1616 0,
1617 (unsigned) height,
1618 (unsigned) MaxCols(screen),
1619 (unsigned) FontWidth(screen));
1620 }
1621 }
1622 ClearBufRows(xw, 0, screen->cur_row - 1);
1623 }
1624
1625 ClearLeft(xw);
1626 }
1627
1628 /*
1629 * Clear from cursor position to end of display, inclusive.
1630 */
1631 static void
1632 ClearBelow(XtermWidget xw)
1633 {
1634 TScreen *screen = TScreenOf(xw);
1635
1636 ClearRight(xw, -1);
1637
1638 if (screen->protected_mode != OFF_PROTECT) {
1639 int row;
1640 unsigned len = (unsigned) MaxCols(screen);
1641
1642 assert(screen->max_col >= 0);
1643 for (row = screen->cur_row + 1; row <= screen->max_row; row++)
1644 ClearInLine(xw, row, 0, len);
1645 } else {
1646 int top;
1647
1648 if ((top = INX2ROW(screen, screen->cur_row)) <= screen->max_row) {
1649 if (screen->scroll_amt)
1650 FlushScroll(xw);
1651 if (++top <= screen->max_row) {
1652 chararea_clear_displayed_graphics(screen,
1653 0,
1654 top,
1655 MaxCols(screen),
1656 (screen->max_row - top + 1));
1657 ClearCurBackground(xw,
1658 top,
1659 0,
1660 (unsigned) (screen->max_row - top + 1),
1661 (unsigned) MaxCols(screen),
1662 (unsigned) FontWidth(screen));
1663 }
1664 }
1665 ClearBufRows(xw, screen->cur_row + 1, screen->max_row);
1666 }
1667 }
1668
1669 /*
1670 * Clear the given row, for the given range of columns, returning 1 if no
1671 * protected characters were found, 0 otherwise.
1672 */
1673 static int
1674 ClearInLine2(XtermWidget xw, int flags, int row, int col, unsigned len)
1675 {
1676 TScreen *screen = TScreenOf(xw);
1677 CLineData *ld;
1678 int rc = 1;
1679
1680 TRACE(("ClearInLine(row=%d, col=%d, len=%d) vs %d..%d\n",
1681 row, col, len,
1682 screen->startH.row,
1683 screen->startH.col));
1684
1685 if (ScrnHaveSelection(screen)
1686 && ScrnIsRowInSelection(screen, row)) {
1687 ScrnDisownSelection(xw);
1688 }
1689
1690 if (col + (int) len >= MaxCols(screen)) {
1691 len = (unsigned) (MaxCols(screen) - col);
1692 }
1693
1694 /* If we've marked protected text on the screen, we'll have to
1695 * check each time we do an erase.
1696 */
1697 if (screen->protected_mode != OFF_PROTECT) {
1698 unsigned n;
1699 IAttr *attrs = getLineData(screen, row)->attribs + col;
1700 int saved_mode = screen->protected_mode;
1701 Bool done;
1702
1703 /* disable this branch during recursion */
1704 screen->protected_mode = OFF_PROTECT;
1705
1706 do {
1707 done = True;
1708 for (n = 0; n < len; n++) {
1709 if (attrs[n] & PROTECTED) {
1710 rc = 0; /* found a protected segment */
1711 if (n != 0) {
1712 ClearInLine(xw, row, col, n);
1713 }
1714 while ((n < len)
1715 && (attrs[n] & PROTECTED)) {
1716 n++;
1717 }
1718 done = False;
1719 break;
1720 }
1721 }
1722 /* setup for another segment, past the protected text */
1723 if (!done) {
1724 attrs += n;
1725 col += (int) n;
1726 len -= n;
1727 }
1728 } while (!done);
1729
1730 screen->protected_mode = saved_mode;
1731 if ((int) len <= 0) {
1732 return 0;
1733 }
1734 }
1735 /* fall through to the final non-protected segment */
1736
1737 if (screen->cursor_state)
1738 HideCursor(xw);
1739 ResetWrap(screen);
1740
1741 if (AddToVisible(xw)
1742 && (ld = getLineData(screen, row)) != 0) {
1743
1744 ClearCurBackground(xw,
1745 INX2ROW(screen, row),
1746 col,
1747 1U,
1748 len,
1749 (unsigned) LineFontWidth(screen, ld));
1750 }
1751
1752 if (len != 0) {
1753 ClearCells(xw, flags, len, row, col);
1754 }
1755
1756 return rc;
1757 }
1758
1759 int
1760 ClearInLine(XtermWidget xw, int row, int col, unsigned len)
1761 {
1762 TScreen *screen = TScreenOf(xw);
1763 int flags = 0;
1764
1765 /*
1766 * If we're clearing to the end of the line, we won't count this as
1767 * "drawn" characters. We'll only do cut/paste on "drawn" characters,
1768 * so this has the effect of suppressing trailing blanks from a
1769 * selection.
1770 */
1771 if (col + (int) len < MaxCols(screen)) {
1772 flags |= CHARDRAWN;
1773 }
1774 return ClearInLine2(xw, flags, row, col, len);
1775 }
1776
1777 /*
1778 * Clear the next n characters on the cursor's line, including the cursor's
1779 * position.
1780 */
1781 void
1782 ClearRight(XtermWidget xw, int n)
1783 {
1784 TScreen *screen = TScreenOf(xw);
1785 LineData *ld;
1786 unsigned len = (unsigned) (MaxCols(screen) - screen->cur_col);
1787
1788 assert(screen->max_col >= 0);
1789 assert(screen->max_col >= screen->cur_col);
1790
1791 if (n < 0) /* the remainder of the line */
1792 n = MaxCols(screen);
1793 if (n == 0) /* default for 'ECH' */
1794 n = 1;
1795
1796 if (len > (unsigned) n)
1797 len = (unsigned) n;
1798
1799 ld = getLineData(screen, screen->cur_row);
1800 if (AddToVisible(xw)) {
1801 if_OPT_WIDE_CHARS(screen, {
1802 int col = screen->cur_col;
1803 int row = screen->cur_row;
1804 int kl;
1805 int kr;
1806 if (DamagedCurCells(screen, len, &kl, &kr) && kr >= kl) {
1807 int xx = col;
1808 if (kl < xx) {
1809 ClearInLine2(xw, 0, row, kl, (unsigned) (xx - kl));
1810 }
1811 xx = col + (int) len - 1;
1812 if (kr > xx) {
1813 ClearInLine2(xw, 0, row, xx + 1, (unsigned) (kr - xx));
1814 }
1815 }
1816 });
1817 (void) ClearInLine(xw, screen->cur_row, screen->cur_col, len);
1818 } else {
1819 ScrnClearCells(xw, screen->cur_row, screen->cur_col, len);
1820 }
1821
1822 /* with the right part cleared, we can't be wrapping */
1823 LineClrWrapped(ld);
1824 ShowWrapMarks(xw, screen->cur_row, ld);
1825 ResetWrap(screen);
1826 }
1827
1828 /*
1829 * Clear first part of cursor's line, inclusive.
1830 */
1831 static void
1832 ClearLeft(XtermWidget xw)
1833 {
1834 TScreen *screen = TScreenOf(xw);
1835 unsigned len = (unsigned) screen->cur_col + 1;
1836
1837 assert(screen->cur_col >= 0);
1838 if (AddToVisible(xw)) {
1839 if_OPT_WIDE_CHARS(screen, {
1840 int row = screen->cur_row;
1841 int kl;
1842 int kr;
1843 if (DamagedCurCells(screen, 1, &kl, &kr) && kr >= kl) {
1844 ClearInLine2(xw, 0, row, kl, (unsigned) (kr - kl + 1));
1845 }
1846 });
1847 (void) ClearInLine(xw, screen->cur_row, 0, len);
1848 } else {
1849 ScrnClearCells(xw, screen->cur_row, 0, len);
1850 }
1851 }
1852
1853 /*
1854 * Erase the cursor's line.
1855 */
1856 void
1857 ClearLine(XtermWidget xw)
1858 {
1859 TScreen *screen = TScreenOf(xw);
1860 unsigned len = (unsigned) MaxCols(screen);
1861
1862 assert(screen->max_col >= 0);
1863 (void) ClearInLine(xw, screen->cur_row, 0, len);
1864 }
1865
1866 void
1867 ClearScreen(XtermWidget xw)
1868 {
1869 TScreen *screen = TScreenOf(xw);
1870 int top;
1871
1872 TRACE(("ClearScreen\n"));
1873
1874 if (screen->cursor_state)
1875 HideCursor(xw);
1876
1877 ScrnDisownSelection(xw);
1878 ResetWrap(screen);
1879 if ((top = INX2ROW(screen, 0)) <= screen->max_row) {
1880 if (screen->scroll_amt)
1881 FlushScroll(xw);
1882 chararea_clear_displayed_graphics(screen,
1883 0,
1884 top,
1885 MaxCols(screen),
1886 (screen->max_row - top + 1));
1887 ClearCurBackground(xw,
1888 top,
1889 0,
1890 (unsigned) (screen->max_row - top + 1),
1891 (unsigned) MaxCols(screen),
1892 (unsigned) FontWidth(screen));
1893 }
1894 ClearBufRows(xw, 0, screen->max_row);
1895 }
1896
1897 /*
1898 * If we've written protected text DEC-style, and are issuing a non-DEC
1899 * erase, temporarily reset the protected_mode flag so that the erase will
1900 * ignore the protected flags.
1901 */
1902 void
1903 do_erase_char(XtermWidget xw, int param, int mode)
1904 {
1905 TScreen *screen = TScreenOf(xw);
1906 int saved_mode = screen->protected_mode;
1907
1908 if (saved_mode == DEC_PROTECT
1909 && saved_mode != mode) {
1910 screen->protected_mode = OFF_PROTECT;
1911 }
1912
1913 ClearRight(xw, param);
1914 screen->protected_mode = saved_mode;
1915 }
1916
1917 void
1918 do_erase_line(XtermWidget xw, int param, int mode)
1919 {
1920 TScreen *screen = TScreenOf(xw);
1921 int saved_mode = screen->protected_mode;
1922
1923 if (saved_mode == DEC_PROTECT
1924 && saved_mode != mode) {
1925 screen->protected_mode = OFF_PROTECT;
1926 }
1927
1928 switch (param) {
1929 case -1: /* DEFAULT */
1930 case 0:
1931 ClearRight(xw, -1);
1932 break;
1933 case 1:
1934 ClearLeft(xw);
1935 break;
1936 case 2:
1937 ClearLine(xw);
1938 break;
1939 }
1940 screen->protected_mode = saved_mode;
1941 }
1942
1943 /*
1944 * Just like 'do_erase_line()', except that this intercepts ED controls. If we
1945 * clear the whole screen, we'll get the return-value from ClearInLine, and
1946 * find if there were any protected characters left. If not, reset the
1947 * protected mode flag in the screen data (it's slower).
1948 */
1949 void
1950 do_erase_display(XtermWidget xw, int param, int mode)
1951 {
1952 TScreen *screen = TScreenOf(xw);
1953 int saved_mode = screen->protected_mode;
1954
1955 if (saved_mode == DEC_PROTECT
1956 && saved_mode != mode)
1957 screen->protected_mode = OFF_PROTECT;
1958
1959 switch (param) {
1960 case -1: /* DEFAULT */
1961 case 0:
1962 if (screen->cur_row == 0
1963 && screen->cur_col == 0) {
1964 screen->protected_mode = saved_mode;
1965 do_erase_display(xw, 2, mode);
1966 saved_mode = screen->protected_mode;
1967 } else
1968 ClearBelow(xw);
1969 break;
1970
1971 case 1:
1972 if (screen->cur_row == screen->max_row
1973 && screen->cur_col == screen->max_col) {
1974 screen->protected_mode = saved_mode;
1975 do_erase_display(xw, 2, mode);
1976 saved_mode = screen->protected_mode;
1977 } else
1978 ClearAbove(xw);
1979 break;
1980
1981 case 2:
1982 /*
1983 * We use 'ClearScreen()' throughout the remainder of the
1984 * program for places where we don't care if the characters are
1985 * protected or not. So we modify the logic around this call
1986 * on 'ClearScreen()' to handle protected characters.
1987 */
1988 if (screen->protected_mode != OFF_PROTECT) {
1989 int row;
1990 int rc = 1;
1991 unsigned len = (unsigned) MaxCols(screen);
1992
1993 assert(screen->max_col >= 0);
1994 for (row = 0; row <= screen->max_row; row++)
1995 rc &= ClearInLine(xw, row, 0, len);
1996 if (rc != 0)
1997 saved_mode = OFF_PROTECT;
1998 } else {
1999 ClearScreen(xw);
2000 }
2001 break;
2002
2003 case 3:
2004 /* xterm addition - erase saved lines. */
2005 if (screen->eraseSavedLines) {
2006 screen->savedlines = 0;
2007 ScrollBarDrawThumb(xw, 1);
2008 }
2009 break;
2010 }
2011 screen->protected_mode = saved_mode;
2012 }
2013
2014 static Boolean
2015 row_has_data(TScreen *screen, int row)
2016 {
2017 Boolean result = False;
2018 CLineData *ld;
2019
2020 if ((ld = getLineData(screen, row)) != 0) {
2021 int col;
2022
2023 for (col = 0; col < screen->max_col; ++col) {
2024 if (ld->attribs[col] & CHARDRAWN && ld->charData[col] != ' ') {
2025 result = True;
2026 break;
2027 }
2028 }
2029 }
2030 return result;
2031 }
2032
2033 static Boolean
2034 screen_has_data(XtermWidget xw)
2035 {
2036 TScreen *screen = TScreenOf(xw);
2037 Boolean result = False;
2038 int row;
2039
2040 for (row = 0; row < screen->max_row; ++row) {
2041 if (row_has_data(screen, row)) {
2042 result = True;
2043 break;
2044 }
2045 }
2046 return result;
2047 }
2048
2049 static void
2050 do_extra_scroll(XtermWidget xw, Bool trimmed)
2051 {
2052 TScreen *screen = TScreenOf(xw);
2053
2054 if (screen_has_data(xw)) {
2055 TRACE(("do_extra_scroll buffer=%d, trimmed=%s\n", screen->whichBuf,
2056 BtoS(trimmed)));
2057 if (trimmed) {
2058 int row;
2059 Boolean hadData = (Boolean) ((screen->saved_fifo > 0)
2060 ? row_has_data(screen, -1)
2061 : False);
2062
2063 for (row = 0; row < screen->max_row; ++row) {
2064 Boolean hasData = row_has_data(screen, row);
2065 if (hasData || hadData) {
2066 LineData *dst = addScrollback(screen);
2067 LineData *src = getLineData(screen, row);
2068 copyLineData(dst, src);
2069 IncrementSavedLines(1);
2070 }
2071 hadData = hasData;
2072 }
2073 } else {
2074 xtermScroll(xw, screen->max_row);
2075 FlushScroll(xw);
2076 }
2077 xtermRepaint(xw);
2078 }
2079 }
2080
2081 /*
2082 * Like tiXtraScroll, perform a scroll up of the page contents.
2083 *
2084 * In this case, it happens for the special case when erasing the whole
2085 * display, e.g., an erase-below starting from the upper-left corner of the
2086 * screen, or if the erasure applies to the whole screen.
2087 */
2088 void
2089 do_cd_xtra_scroll(XtermWidget xw, int param)
2090 {
2091 TScreen *screen = TScreenOf(xw);
2092
2093 TRACE(("do_cd_xtra_scroll param %d, @%d,%d vs %d,%d\n", param,
2094 screen->cur_row,
2095 screen->cur_col,
2096 ScrnTopMargin(xw),
2097 ScrnLeftMargin(xw)));
2098 if (xw->misc.cdXtraScroll
2099 && (param == 2 ||
2100 (param == 0
2101 && screen->cur_col <= ScrnLeftMargin(xw)
2102 && screen->cur_row <= ScrnTopMargin(xw)))) {
2103 do_extra_scroll(xw, (xw->misc.cdXtraScroll == edTrim));
2104 }
2105 }
2106
2107 /*
2108 * Scroll the page up (saving it). This is called when doing terminal
2109 * initialization (ti) or exiting from that (te).
2110 */
2111 void
2112 do_ti_xtra_scroll(XtermWidget xw)
2113 {
2114 if (xw->misc.tiXtraScroll) {
2115 do_extra_scroll(xw, False);
2116 }
2117 }
2118
2119 static void
2120 CopyWait(XtermWidget xw)
2121 {
2122 TScreen *screen = TScreenOf(xw);
2123 XEvent reply;
2124 XEvent *rep = &reply;
2125 #ifndef NO_ACTIVE_ICON
2126 int retries = 0;
2127 #endif
2128
2129 #if USE_DOUBLE_BUFFER
2130 if (resource.buffered)
2131 return;
2132 #endif
2133
2134 for (;;) {
2135 #ifndef NO_ACTIVE_ICON
2136 if (xw->work.active_icon != eiFalse) {
2137 /*
2138 * The XWindowEvent call blocks until an event is available. That
2139 * can hang when using active-icon and iconifying/deiconifying
2140 * while the terminal is receiving lots of output. Checking with
2141 * this call on the other hand may lose exposure events which
2142 * arrive too late. As a compromise, try several times with a
2143 * time-delay before assuming no more events are available.
2144 */
2145 if (XCheckWindowEvent(screen->display,
2146 VWindow(screen),
2147 ExposureMask,
2148 &reply)) {
2149 retries = 0;
2150 } else {
2151 if (++retries >= 1000)
2152 return;
2153 usleep(100U); /* wait 0.1msec */
2154 continue;
2155 }
2156 } else
2157 #endif
2158 XWindowEvent(screen->display, VWindow(screen), ExposureMask, &reply);
2159 switch (reply.type) {
2160 case Expose:
2161 HandleExposure(xw, &reply);
2162 break;
2163 case NoExpose:
2164 case GraphicsExpose:
2165 if (screen->incopy <= 0) {
2166 screen->incopy = 1;
2167 if (screen->scrolls > 0)
2168 screen->scrolls--;
2169 }
2170 if (reply.type == GraphicsExpose)
2171 HandleExposure(xw, &reply);
2172
2173 if ((reply.type == NoExpose) ||
2174 ((XExposeEvent *) rep)->count == 0) {
2175 if (screen->incopy <= 0 && screen->scrolls > 0)
2176 screen->scrolls--;
2177 if (screen->scrolls == 0) {
2178 screen->incopy = 0;
2179 return;
2180 }
2181 screen->incopy = -1;
2182 }
2183 break;
2184 }
2185 }
2186 }
2187
2188 /*
2189 * used by vertical_copy_area and and horizontal_copy_area
2190 */
2191 static void
2192 copy_area(XtermWidget xw,
2193 int src_x,
2194 int src_y,
2195 unsigned width,
2196 unsigned height,
2197 int dest_x,
2198 int dest_y)
2199 {
2200 TScreen *screen = TScreenOf(xw);
2201
2202 if (width != 0 && height != 0) {
2203 /* wait for previous CopyArea to complete unless
2204 multiscroll is enabled and active */
2205 if (screen->incopy && screen->scrolls == 0)
2206 CopyWait(xw);
2207 screen->incopy = -1;
2208
2209 /* save for translating Expose events */
2210 screen->copy_src_x = src_x;
2211 screen->copy_src_y = src_y;
2212 screen->copy_width = width;
2213 screen->copy_height = height;
2214 screen->copy_dest_x = dest_x;
2215 screen->copy_dest_y = dest_y;
2216
2217 XCopyArea(screen->display,
2218 VDrawable(screen), VDrawable(screen),
2219 NormalGC(xw, screen),
2220 src_x, src_y, width, height, dest_x, dest_y);
2221 }
2222 }
2223
2224 /*
2225 * use when inserting or deleting characters on the current line
2226 */
2227 static void
2228 horizontal_copy_area(XtermWidget xw,
2229 int firstchar, /* char pos on screen to start copying at */
2230 int nchars,
2231 int amount) /* number of characters to move right */
2232 {
2233 TScreen *screen = TScreenOf(xw);
2234 CLineData *ld;
2235
2236 if ((ld = getLineData(screen, screen->cur_row)) != 0) {
2237 int src_x = LineCursorX(screen, ld, firstchar);
2238 int src_y = CursorY(screen, screen->cur_row);
2239
2240 copy_area(xw, src_x, src_y,
2241 (unsigned) (nchars * LineFontWidth(screen, ld)),
2242 (unsigned) FontHeight(screen),
2243 src_x + amount * LineFontWidth(screen, ld), src_y);
2244 }
2245 }
2246
2247 /*
2248 * use when inserting or deleting lines from the screen
2249 */
2250 static void
2251 vertical_copy_area(XtermWidget xw,
2252 int firstline, /* line on screen to start copying at */
2253 int nlines,
2254 int amount, /* number of lines to move up (neg=down) */
2255 int left,
2256 int right)
2257 {
2258 TScreen *screen = TScreenOf(xw);
2259
2260 TRACE(("vertical_copy_area - firstline=%d nlines=%d left=%d right=%d amount=%d\n",
2261 firstline, nlines, left, right, amount));
2262
2263 if (nlines > 0) {
2264 int src_x = CursorX(screen, left);
2265 int src_y = firstline * FontHeight(screen) + screen->border;
2266 unsigned int w = (unsigned) ((right + 1 - left) * FontWidth(screen));
2267 unsigned int h = (unsigned) (nlines * FontHeight(screen));
2268 int dst_x = src_x;
2269 int dst_y = src_y - amount * FontHeight(screen);
2270
2271 copy_area(xw, src_x, src_y, w, h, dst_x, dst_y);
2272
2273 if (screen->show_wrap_marks) {
2274 int row;
2275 int first = firstline - amount;
2276 int last = firstline + nlines + amount;
2277
2278 for (row = first; row < last; ++row) {
2279 CLineData *ld;
2280 int mapped = amount + row + screen->topline;
2281
2282 if ((ld = getLineData(screen, mapped)) != 0) {
2283 ShowWrapMarks(xw, row, ld);
2284 }
2285 }
2286 }
2287 }
2288 }
2289
2290 /*
2291 * use when scrolling the entire screen
2292 */
2293 void
2294 scrolling_copy_area(XtermWidget xw,
2295 int firstline, /* line on screen to start copying at */
2296 int nlines,
2297 int amount) /* number of lines to move up (neg=down) */
2298 {
2299
2300 if (nlines > 0) {
2301 vertical_copy_area(xw, firstline, nlines, amount, 0, TScreenOf(xw)->max_col);
2302 }
2303 }
2304
2305 /*
2306 * Handler for Expose events on the VT widget.
2307 * Returns 1 iff the area where the cursor was got refreshed.
2308 */
2309 int
2310 HandleExposure(XtermWidget xw, XEvent *event)
2311 {
2312 TScreen *screen = TScreenOf(xw);
2313 XExposeEvent *reply = (XExposeEvent *) event;
2314
2315 #ifndef NO_ACTIVE_ICON
2316 if (reply->window == screen->iconVwin.window) {
2317 WhichVWin(screen) = &screen->iconVwin;
2318 TRACE(("HandleExposure - icon\n"));
2319 } else {
2320 WhichVWin(screen) = &screen->fullVwin;
2321 TRACE(("HandleExposure - normal\n"));
2322 }
2323 TRACE((" event %d,%d %dx%d\n",
2324 reply->y,
2325 reply->x,
2326 reply->height,
2327 reply->width));
2328 #endif /* NO_ACTIVE_ICON */
2329
2330 /* if not doing CopyArea or if this is a GraphicsExpose, don't translate */
2331 if (!screen->incopy || event->type != Expose) {
2332 return handle_translated_exposure(xw, reply->x, reply->y,
2333 reply->width,
2334 reply->height);
2335 } else {
2336 /* compute intersection of area being copied with
2337 area being exposed. */
2338 int both_x1 = Max(screen->copy_src_x, reply->x);
2339 int both_y1 = Max(screen->copy_src_y, reply->y);
2340 int both_x2 = Min(screen->copy_src_x + (int) screen->copy_width,
2341 (reply->x + (int) reply->width));
2342 int both_y2 = Min(screen->copy_src_y + (int) screen->copy_height,
2343 (reply->y + (int) reply->height));
2344 int value = 0;
2345
2346 /* was anything copied affected? */
2347 if (both_x2 > both_x1 && both_y2 > both_y1) {
2348 /* do the copied area */
2349 value = handle_translated_exposure
2350 (xw, reply->x + screen->copy_dest_x - screen->copy_src_x,
2351 reply->y + screen->copy_dest_y - screen->copy_src_y,
2352 reply->width, reply->height);
2353 }
2354 /* was anything not copied affected? */
2355 if (reply->x < both_x1 || reply->y < both_y1
2356 || reply->x + reply->width > both_x2
2357 || reply->y + reply->height > both_y2)
2358 value = handle_translated_exposure(xw, reply->x, reply->y,
2359 reply->width, reply->height);
2360
2361 return value;
2362 }
2363 }
2364
2365 static void
2366 set_background(XtermWidget xw, int color)
2367 {
2368 TScreen *screen = TScreenOf(xw);
2369 Pixel c = getXtermBG(xw, xw->flags, color);
2370
2371 #if OPT_WIDE_ATTRS
2372 TRACE(("set_background(%d) %#lx %s\n", color, c,
2373 ((xw->flags & ATR_DIRECT_BG)
2374 ? "direct"
2375 : "indexed")));
2376 #else
2377 TRACE(("set_background(%d) %#lx\n", color, c));
2378 #endif
2379 XSetWindowBackground(screen->display, VShellWindow(xw), c);
2380 XSetWindowBackground(screen->display, VWindow(screen), c);
2381 initBorderGC(xw, WhichVWin(screen));
2382 }
2383
2384 void
2385 xtermClear2(XtermWidget xw, int x, int y, unsigned width, unsigned height)
2386 {
2387 TScreen *screen = TScreenOf(xw);
2388 VTwin *vwin = WhichVWin(screen);
2389 Drawable draw = VDrawable(screen);
2390 GC gc;
2391
2392 if ((gc = vwin->border_gc) != 0) {
2393 int vmark1 = screen->border;
2394 int vmark2 = vwin->height + vmark1;
2395 int hmark1 = OriginX(screen);
2396 int hmark2 = vwin->width + hmark1;
2397 if (y < vmark1) {
2398 int yy = y + (int) height;
2399 int h1 = (yy <= vmark1) ? (yy - y) : (vmark1 - y);
2400 XFillRectangle(screen->display, draw, gc,
2401 x, y, width, (unsigned) h1);
2402 if (yy > vmark1) {
2403 xtermClear2(xw, x, vmark1, width, (unsigned) (yy - vmark1));
2404 }
2405 } else if (y < vmark2) {
2406 int yy = y + (int) height;
2407 int h2 = (yy <= vmark2) ? (yy - y) : (vmark2 - y);
2408 int xb = x;
2409 int xx = x + (int) width;
2410 int ww = (int) width;
2411 if (x < hmark1) {
2412 int w1 = (xx <= hmark1) ? (xx - x) : (hmark1 - x);
2413 XFillRectangle(screen->display, draw, gc,
2414 x, y, (unsigned) w1, (unsigned) h2);
2415 x += w1;
2416 ww -= w1;
2417 }
2418 if ((ww > 0) && (x < hmark2)) {
2419 int w2 = (xx <= hmark2) ? (xx - x) : (hmark2 - x);
2420 #if USE_DOUBLE_BUFFER
2421 if (resource.buffered) {
2422 XFillRectangle(screen->display, draw,
2423 FillerGC(xw, screen),
2424 x, y, (unsigned) w2, (unsigned) h2);
2425 } else
2426 #endif
2427 XClearArea(screen->display, VWindow(screen),
2428 x, y, (unsigned) w2, (unsigned) h2, False);
2429 x += w2;
2430 ww -= w2;
2431 }
2432 if (ww > 0) {
2433 XFillRectangle(screen->display, draw, gc,
2434 x, y, (unsigned) ww, (unsigned) h2);
2435 }
2436 if (yy > vmark2) {
2437 xtermClear2(xw, xb, vmark2, width, (unsigned) (yy - vmark2));
2438 }
2439 } else {
2440 XFillRectangle(screen->display, draw, gc, x, y, width, height);
2441 }
2442 } else {
2443 #if USE_DOUBLE_BUFFER
2444 if (resource.buffered) {
2445 gc = FillerGC(xw, screen);
2446 XFillRectangle(screen->display, draw, gc,
2447 x, y, width, height);
2448 } else
2449 #endif
2450 XClearArea(screen->display,
2451 VWindow(screen),
2452 x, y, width, height, False);
2453 }
2454 }
2455
2456 /*
2457 * Called by the ExposeHandler to do the actual repaint after the coordinates
2458 * have been translated to allow for any CopyArea in progress.
2459 * The rectangle passed in is pixel coordinates.
2460 */
2461 static int
2462 handle_translated_exposure(XtermWidget xw,
2463 int rect_x,
2464 int rect_y,
2465 int rect_width,
2466 int rect_height)
2467 {
2468 TScreen *screen = TScreenOf(xw);
2469 int toprow, leftcol, nrows, ncols;
2470 int x0, x1;
2471 int y0, y1;
2472 int result = 0;
2473
2474 TRACE(("handle_translated_exposure at %d,%d size %dx%d\n",
2475 rect_y, rect_x, rect_height, rect_width));
2476
2477 x0 = (rect_x - OriginX(screen));
2478 x1 = (x0 + rect_width);
2479
2480 y0 = (rect_y - OriginY(screen));
2481 y1 = (y0 + rect_height);
2482
2483 if (x0 < 0 ||
2484 y0 < 0 ||
2485 x1 > Width(screen) ||
2486 y1 > PlusStatusLine(screen, Height(screen))) {
2487 set_background(xw, -1);
2488 xtermClear2(xw,
2489 rect_x,
2490 rect_y,
2491 (unsigned) rect_width,
2492 (unsigned) rect_height);
2493 }
2494 toprow = y0 / FontHeight(screen);
2495 if (toprow < 0)
2496 toprow = 0;
2497
2498 leftcol = x0 / FontWidth(screen);
2499 if (leftcol < 0)
2500 leftcol = 0;
2501
2502 nrows = (y1 - 1) / FontHeight(screen) - toprow + 1;
2503 ncols = (x1 - 1) / FontWidth(screen) - leftcol + 1;
2504 toprow -= screen->scrolls;
2505 if (toprow < 0) {
2506 nrows += toprow;
2507 toprow = 0;
2508 }
2509 if (toprow + nrows > PlusStatusLine(screen, MaxRows(screen)))
2510 nrows = PlusStatusLine(screen, MaxRows(screen)) - toprow;
2511 if (leftcol + ncols > MaxCols(screen))
2512 ncols = MaxCols(screen) - leftcol;
2513
2514 if (nrows > 0 && ncols > 0) {
2515 ScrnRefresh(xw, toprow, leftcol, nrows, ncols, True);
2516 first_map_occurred();
2517 if (screen->cur_row >= toprow &&
2518 screen->cur_row < toprow + nrows &&
2519 screen->cur_col >= leftcol &&
2520 screen->cur_col < leftcol + ncols) {
2521 result = 1;
2522 }
2523
2524 }
2525 TRACE(("...handle_translated_exposure %d\n", result));
2526 return (result);
2527 }
2528
2529 /***====================================================================***/
2530
2531 void
2532 GetColors(XtermWidget xw, ScrnColors * pColors)
2533 {
2534 TScreen *screen = TScreenOf(xw);
2535 int n;
2536
2537 pColors->which = 0;
2538 for (n = 0; n < NCOLORS; ++n) {
2539 SET_COLOR_VALUE(pColors, n, T_COLOR(screen, n));
2540 }
2541 }
2542
2543 void
2544 ChangeColors(XtermWidget xw, ScrnColors * pNew)
2545 {
2546 Bool repaint = False;
2547 TScreen *screen = TScreenOf(xw);
2548 VTwin *win = WhichVWin(screen);
2549
2550 TRACE(("ChangeColors\n"));
2551
2552 if (COLOR_DEFINED(pNew, TEXT_CURSOR)) {
2553 T_COLOR(screen, TEXT_CURSOR) = COLOR_VALUE(pNew, TEXT_CURSOR);
2554 TRACE(("... TEXT_CURSOR: %#lx\n", T_COLOR(screen, TEXT_CURSOR)));
2555 FreeMarkGCs(xw);
2556 /* no repaint needed */
2557 } else if ((T_COLOR(screen, TEXT_CURSOR) == T_COLOR(screen, TEXT_FG)) &&
2558 (COLOR_DEFINED(pNew, TEXT_FG))) {
2559 if (T_COLOR(screen, TEXT_CURSOR) != COLOR_VALUE(pNew, TEXT_FG)) {
2560 T_COLOR(screen, TEXT_CURSOR) = COLOR_VALUE(pNew, TEXT_FG);
2561 TRACE(("... TEXT_CURSOR: %#lx\n", T_COLOR(screen, TEXT_CURSOR)));
2562 if (screen->Vshow)
2563 repaint = True;
2564 }
2565 FreeMarkGCs(xw);
2566 }
2567
2568 if (COLOR_DEFINED(pNew, TEXT_FG)) {
2569 Pixel fg = COLOR_VALUE(pNew, TEXT_FG);
2570 T_COLOR(screen, TEXT_FG) = fg;
2571 TRACE(("... TEXT_FG: %#lx\n", T_COLOR(screen, TEXT_FG)));
2572 if (screen->Vshow) {
2573 setCgsFore(xw, win, gcNorm, fg);
2574 setCgsBack(xw, win, gcNormReverse, fg);
2575 setCgsFore(xw, win, gcBold, fg);
2576 setCgsBack(xw, win, gcBoldReverse, fg);
2577 repaint = True;
2578 }
2579 FreeMarkGCs(xw);
2580 }
2581
2582 if (COLOR_DEFINED(pNew, TEXT_BG)) {
2583 Pixel bg = COLOR_VALUE(pNew, TEXT_BG);
2584 T_COLOR(screen, TEXT_BG) = bg;
2585 TRACE(("... TEXT_BG: %#lx\n", T_COLOR(screen, TEXT_BG)));
2586 if (screen->Vshow) {
2587 setCgsBack(xw, win, gcNorm, bg);
2588 setCgsFore(xw, win, gcNormReverse, bg);
2589 setCgsBack(xw, win, gcBold, bg);
2590 setCgsFore(xw, win, gcBoldReverse, bg);
2591 set_background(xw, -1);
2592 repaint = True;
2593 }
2594 }
2595 #if OPT_HIGHLIGHT_COLOR
2596 if (COLOR_DEFINED(pNew, HIGHLIGHT_BG)) {
2597 if (T_COLOR(screen, HIGHLIGHT_BG) != COLOR_VALUE(pNew, HIGHLIGHT_BG)) {
2598 T_COLOR(screen, HIGHLIGHT_BG) = COLOR_VALUE(pNew, HIGHLIGHT_BG);
2599 TRACE(("... HIGHLIGHT_BG: %#lx\n", T_COLOR(screen, HIGHLIGHT_BG)));
2600 if (screen->Vshow)
2601 repaint = True;
2602 }
2603 }
2604 if (COLOR_DEFINED(pNew, HIGHLIGHT_FG)) {
2605 if (T_COLOR(screen, HIGHLIGHT_FG) != COLOR_VALUE(pNew, HIGHLIGHT_FG)) {
2606 T_COLOR(screen, HIGHLIGHT_FG) = COLOR_VALUE(pNew, HIGHLIGHT_FG);
2607 TRACE(("... HIGHLIGHT_FG: %#lx\n", T_COLOR(screen, HIGHLIGHT_FG)));
2608 if (screen->Vshow)
2609 repaint = True;
2610 }
2611 }
2612 #endif
2613
2614 if (COLOR_DEFINED(pNew, MOUSE_FG) || (COLOR_DEFINED(pNew, MOUSE_BG))) {
2615 if (COLOR_DEFINED(pNew, MOUSE_FG)) {
2616 T_COLOR(screen, MOUSE_FG) = COLOR_VALUE(pNew, MOUSE_FG);
2617 TRACE(("... MOUSE_FG: %#lx\n", T_COLOR(screen, MOUSE_FG)));
2618 }
2619 if (COLOR_DEFINED(pNew, MOUSE_BG)) {
2620 T_COLOR(screen, MOUSE_BG) = COLOR_VALUE(pNew, MOUSE_BG);
2621 TRACE(("... MOUSE_BG: %#lx\n", T_COLOR(screen, MOUSE_BG)));
2622 }
2623
2624 if (screen->Vshow) {
2625 recolor_cursor(screen,
2626 screen->pointer_cursor,
2627 T_COLOR(screen, MOUSE_FG),
2628 T_COLOR(screen, MOUSE_BG));
2629 XDefineCursor(screen->display, VWindow(screen),
2630 screen->pointer_cursor);
2631 }
2632 #if OPT_TEK4014
2633 if (TEK4014_SHOWN(xw)) {
2634 TekScreen *tekscr = TekScreenOf(tekWidget);
2635 Window tekwin = TWindow(tekscr);
2636 if (tekwin) {
2637 recolor_cursor(screen,
2638 tekscr->arrow,
2639 T_COLOR(screen, MOUSE_FG),
2640 T_COLOR(screen, MOUSE_BG));
2641 XDefineCursor(screen->display, tekwin, tekscr->arrow);
2642 }
2643 }
2644 #endif
2645 /* no repaint needed */
2646 }
2647
2648 if (COLOR_DEFINED(pNew, TEXT_FG) ||
2649 COLOR_DEFINED(pNew, TEXT_BG) ||
2650 COLOR_DEFINED(pNew, TEXT_CURSOR)) {
2651 if (set_cursor_gcs(xw) && screen->Vshow) {
2652 repaint = True;
2653 }
2654 }
2655 #if OPT_TEK4014
2656 if (COLOR_DEFINED(pNew, TEK_FG) ||
2657 COLOR_DEFINED(pNew, TEK_BG)) {
2658 ChangeTekColors(tekWidget, screen, pNew);
2659 if (TEK4014_SHOWN(xw)) {
2660 TekRepaint(tekWidget);
2661 }
2662 } else if (COLOR_DEFINED(pNew, TEK_CURSOR)) {
2663 ChangeTekColors(tekWidget, screen, pNew);
2664 }
2665 #endif
2666 if (repaint)
2667 xtermRepaint(xw);
2668 }
2669
2670 void
2671 xtermClear(XtermWidget xw)
2672 {
2673 TScreen *screen = TScreenOf(xw);
2674
2675 TRACE(("xtermClear\n"));
2676 xtermClear2(xw, 0, 0, FullWidth(screen), FullHeight(screen));
2677 }
2678
2679 void
2680 xtermRepaint(XtermWidget xw)
2681 {
2682 TScreen *screen = TScreenOf(xw);
2683
2684 TRACE(("xtermRepaint\n"));
2685 xtermClear(xw);
2686 ScrnRefresh(xw, 0, 0, LastRowNumber(screen) + 1, MaxCols(screen), True);
2687 }
2688
2689 /***====================================================================***/
2690
2691 Boolean
2692 isDefaultForeground(const char *name)
2693 {
2694 return (Boolean) !x_strcasecmp(name, XtDefaultForeground);
2695 }
2696
2697 Boolean
2698 isDefaultBackground(const char *name)
2699 {
2700 return (Boolean) !x_strcasecmp(name, XtDefaultBackground);
2701 }
2702
2703 /***====================================================================***/
2704
2705 typedef struct {
2706 Pixel fg;
2707 Pixel bg;
2708 } ToSwap;
2709
2710 #if OPT_HIGHLIGHT_COLOR
2711 #define hc_param ,Bool hilite_color
2712 #define hc_value ,screen->hilite_color
2713 #else
2714 #define hc_param /* nothing */
2715 #define hc_value /* nothing */
2716 #endif
2717
2718 /*
2719 * Use this to swap the foreground/background color values in the resource
2720 * data, and to build up a list of the pairs which must be swapped in the
2721 * GC cache.
2722 */
2723 static void
2724 swapLocally(ToSwap * list, int *count, ColorRes * fg, ColorRes * bg hc_param)
2725 {
2726 ColorRes tmp;
2727 Boolean found = False;
2728
2729 Pixel fg_color = fg->value;
2730 Pixel bg_color = bg->value;
2731
2732 #if OPT_HIGHLIGHT_COLOR
2733 if ((fg_color != bg_color) || !hilite_color)
2734 #endif
2735 {
2736 int n;
2737
2738 EXCHANGE(*fg, *bg, tmp);
2739 for (n = 0; n < *count; ++n) {
2740 if ((list[n].fg == fg_color && list[n].bg == bg_color)
2741 || (list[n].fg == bg_color && list[n].bg == fg_color)) {
2742 found = True;
2743 break;
2744 }
2745 }
2746 if (!found) {
2747 list[*count].fg = fg_color;
2748 list[*count].bg = bg_color;
2749 *count = *count + 1;
2750 TRACE(("swapLocally fg %#lx, bg %#lx ->%d\n",
2751 fg_color, bg_color, *count));
2752 }
2753 }
2754 }
2755
2756 static void
2757 reallySwapColors(XtermWidget xw, ToSwap * list, int count)
2758 {
2759 int j, k;
2760
2761 TRACE(("reallySwapColors\n"));
2762 for (j = 0; j < count; ++j) {
2763 for_each_text_gc(k) {
2764 redoCgs(xw, list[j].fg, list[j].bg, (CgsEnum) k);
2765 }
2766 }
2767 FreeMarkGCs(xw);
2768 }
2769
2770 static void
2771 swapVTwinGCs(XtermWidget xw, VTwin *win)
2772 {
2773 swapCgs(xw, win, gcNorm, gcNormReverse);
2774 swapCgs(xw, win, gcBold, gcBoldReverse);
2775 }
2776
2777 void
2778 ReverseVideo(XtermWidget xw)
2779 {
2780 TScreen *screen = TScreenOf(xw);
2781 ToSwap listToSwap[5];
2782 int numToSwap = 0;
2783
2784 TRACE(("ReverseVideo now %s\n", BtoS(xw->misc.re_verse)));
2785
2786 /*
2787 * Swap SGR foreground and background colors. By convention, these are
2788 * the colors assigned to "black" (SGR #0) and "white" (SGR #7). Also,
2789 * SGR #8 and SGR #15 are the bold (or bright) versions of SGR #0 and
2790 * #7, respectively.
2791 *
2792 * We don't swap colors that happen to match the screen's foreground
2793 * and background because that tends to produce bizarre effects.
2794 */
2795 #define swapAnyColor(name,a,b) swapLocally(listToSwap, &numToSwap, &(screen->name[a]), &(screen->name[b]) hc_value)
2796 #define swapAColor(a,b) swapAnyColor(Acolors, a, b)
2797 if_OPT_ISO_COLORS(screen, {
2798 swapAColor(0, 7);
2799 swapAColor(8, 15);
2800 });
2801
2802 if (T_COLOR(screen, TEXT_CURSOR) == T_COLOR(screen, TEXT_FG)) {
2803 T_COLOR(screen, TEXT_CURSOR) = T_COLOR(screen, TEXT_BG);
2804 }
2805 #define swapTColor(a,b) swapAnyColor(Tcolors, a, b)
2806 swapTColor(TEXT_FG, TEXT_BG);
2807 swapTColor(MOUSE_FG, MOUSE_BG);
2808
2809 reallySwapColors(xw, listToSwap, numToSwap);
2810
2811 swapVTwinGCs(xw, &(screen->fullVwin));
2812 #ifndef NO_ACTIVE_ICON
2813 swapVTwinGCs(xw, &(screen->iconVwin));
2814 #endif /* NO_ACTIVE_ICON */
2815
2816 xw->misc.re_verse = (Boolean) !xw->misc.re_verse;
2817 TRACE(("...swapping done, set ReverseVideo %s\n", BtoS(xw->misc.re_verse)));
2818
2819 if (XtIsRealized((Widget) xw)) {
2820 xtermDisplayPointer(xw);
2821 }
2822 #if OPT_TEK4014
2823 if (TEK4014_SHOWN(xw)) {
2824 TekScreen *tekscr = TekScreenOf(tekWidget);
2825 Window tekwin = TWindow(tekscr);
2826 recolor_cursor(screen,
2827 tekscr->arrow,
2828 T_COLOR(screen, MOUSE_FG),
2829 T_COLOR(screen, MOUSE_BG));
2830 XDefineCursor(screen->display, tekwin, tekscr->arrow);
2831 }
2832 #endif
2833
2834 if (screen->scrollWidget)
2835 ScrollBarReverseVideo(screen->scrollWidget);
2836
2837 if (XtIsRealized((Widget) xw)) {
2838 set_background(xw, -1);
2839 }
2840 #if OPT_TEK4014
2841 TekReverseVideo(xw, tekWidget);
2842 #endif
2843 if (XtIsRealized((Widget) xw)) {
2844 xtermRepaint(xw);
2845 }
2846 #if OPT_TEK4014
2847 if (TEK4014_SHOWN(xw)) {
2848 TekRepaint(tekWidget);
2849 }
2850 #endif
2851 ReverseOldColors(xw);
2852 set_cursor_gcs(xw);
2853 update_reversevideo();
2854 TRACE(("...ReverseVideo now %s\n", BtoS(xw->misc.re_verse)));
2855 }
2856
2857 void
2858 recolor_cursor(TScreen *screen,
2859 Cursor cursor, /* X cursor ID to set */
2860 unsigned long fg, /* pixel indexes to look up */
2861 unsigned long bg) /* pixel indexes to look up */
2862 {
2863 Display *dpy = screen->display;
2864 XColor colordefs[2]; /* 0 is foreground, 1 is background */
2865
2866 colordefs[0].pixel = fg;
2867 colordefs[1].pixel = bg;
2868 XQueryColors(dpy, DefaultColormap(dpy, DefaultScreen(dpy)),
2869 colordefs, 2);
2870 XRecolorCursor(dpy, cursor, colordefs, colordefs + 1);
2871 cleanup_colored_cursor();
2872 return;
2873 }
2874
2875 #if OPT_RENDERFONT
2876 #define XFT_CACHE_LIMIT ((unsigned)(~0) >> 1)
2877 #define XFT_CACHE_SIZE 16
2878 typedef struct {
2879 XftColor color;
2880 unsigned use;
2881 } XftColorCache;
2882
2883 static int
2884 compare_xft_color_cache(const void *a, const void *b)
2885 {
2886 return (int) (((const XftColorCache *) a)->use -
2887 ((const XftColorCache *) b)->use);
2888 }
2889
2890 static XftColor *
2891 getXftColor(XtermWidget xw, Pixel pixel)
2892 {
2893 static XftColorCache cache[XFT_CACHE_SIZE + 1];
2894 static unsigned latest_use;
2895 int i;
2896 int oldest;
2897 unsigned oldest_use;
2898 XColor color;
2899 Boolean found = False;
2900
2901 (void) xw;
2902 oldest_use = XFT_CACHE_LIMIT;
2903 oldest = 0;
2904 if (latest_use == XFT_CACHE_LIMIT) {
2905 latest_use = 0;
2906 qsort(cache, (size_t) XFT_CACHE_SIZE, sizeof(XftColorCache), compare_xft_color_cache);
2907 for (i = 0; i < XFT_CACHE_SIZE; i++) {
2908 if (cache[i].use) {
2909 cache[i].use = ++latest_use;
2910 }
2911 }
2912 }
2913 for (i = 0; i < XFT_CACHE_SIZE; i++) {
2914 if (cache[i].use) {
2915 if (cache[i].color.pixel == pixel) {
2916 found = True;
2917 break;
2918 }
2919 }
2920 if (cache[i].use < oldest_use) {
2921 oldest_use = cache[i].use;
2922 oldest = i;
2923 }
2924 }
2925 if (!found) {
2926 i = oldest;
2927 color.pixel = pixel;
2928 (void) QueryOneColor(xw, &color);
2929 cache[i].color.color.red = color.red;
2930 cache[i].color.color.green = color.green;
2931 cache[i].color.color.blue = color.blue;
2932 cache[i].color.color.alpha = 0xffff;
2933 cache[i].color.pixel = pixel;
2934 }
2935 cache[i].use = ++latest_use;
2936 return &cache[i].color;
2937 }
2938
2939 /*
2940 * The cell-width is related to, but not the same as the wide-character width.
2941 * We will only get useful values from wcwidth() for codes above 255.
2942 * Otherwise, interpret according to internal data.
2943 */
2944 #if OPT_RENDERWIDE
2945
2946 #if OPT_C1_PRINT
2947 #define XtermCellWidth(xw, ch) \
2948 (((ch) == 0 || (ch) == 127) \
2949 ? 0 \
2950 : (((ch) < 256) \
2951 ? (((ch) >= 128 && (ch) < 160) \
2952 ? (TScreenOf(xw)->c1_printable ? 1 : 0) \
2953 : 1) \
2954 : CharWidth(TScreenOf(xw), ch)))
2955 #else
2956 #define XtermCellWidth(xw, ch) \
2957 (((ch) == 0 || (ch) == 127) \
2958 ? 0 \
2959 : (((ch) < 256) \
2960 ? 1 \
2961 : CharWidth(TScreenOf(xw), ch)))
2962 #endif
2963
2964 #endif /* OPT_RENDERWIDE */
2965
2966 #define XFT_DATA(which) getMyXftFont(params->xw, which, fontnum)
2967
2968 #if OPT_ISO_COLORS
2969 #define UseBoldFont(screen) (!(screen)->colorBDMode || ((screen)->veryBoldColors & BOLD))
2970 #else
2971 #define UseBoldFont(screen) 1
2972 #endif
2973
2974 #if OPT_RENDERWIDE
2975 /*
2976 * Find Xft (truetype) double-width font for the given normal/bold attributes.
2977 */
2978 static XTermXftFonts *
2979 getWideXftFont(XTermDraw * params,
2980 unsigned attr_flags)
2981 {
2982 TScreen *screen = TScreenOf(params->xw);
2983 int fontnum = screen->menu_font_number;
2984 XTermXftFonts *result = 0;
2985
2986 #if OPT_WIDE_ATTRS
2987 if ((attr_flags & ATR_ITALIC)
2988 #if OPT_ISO_COLORS
2989 && !screen->colorITMode
2990 #endif
2991 ) {
2992 if ((attr_flags & BOLDATTR(screen))
2993 && UseBoldFont(screen)
2994 && XFT_DATA(fWBtal)) {
2995 result = XFT_DATA(fWBtal);
2996 } else if (XFT_DATA(fWItal)) {
2997 result = XFT_DATA(fWItal);
2998 }
2999 }
3000 if (result != 0) {
3001 ; /* skip the other tests */
3002 } else
3003 #endif
3004 #if OPT_ISO_COLORS
3005 if ((attr_flags & UNDERLINE)
3006 && !screen->colorULMode
3007 && screen->italicULMode
3008 && XFT_DATA(fWItal)) {
3009 result = XFT_DATA(fWItal);
3010 } else
3011 #endif
3012 if ((attr_flags & BOLDATTR(screen))
3013 && UseBoldFont(screen)
3014 && XFT_DATA(fWBold)) {
3015 result = XFT_DATA(fWBold);
3016 } else {
3017 result = XFT_DATA(fWide);
3018 }
3019 return result;
3020 }
3021 #endif /* OPT_RENDERWIDE */
3022
3023 /*
3024 * Find Xft (truetype) single-width font for the given normal/bold attributes.
3025 */
3026 static XTermXftFonts *
3027 getNormXftFont(XTermDraw * params,
3028 unsigned attr_flags,
3029 Bool *did_ul)
3030 {
3031 TScreen *screen = TScreenOf(params->xw);
3032 int fontnum = screen->menu_font_number;
3033 XTermXftFonts *result = NULL;
3034
3035 (void) did_ul;
3036 #if OPT_DEC_CHRSET
3037 if (CSET_DOUBLE(params->real_chrset)) {
3038 result = xterm_DoubleFT(params, params->real_chrset, attr_flags);
3039 }
3040 if (result != 0) {
3041 ; /* found a usable double-sized font */
3042 } else
3043 #endif
3044 #if OPT_WIDE_ATTRS
3045 if ((attr_flags & ATR_ITALIC)
3046 #if OPT_ISO_COLORS
3047 && !screen->colorITMode
3048 #endif
3049 ) {
3050 if ((attr_flags & BOLDATTR(screen))
3051 && UseBoldFont(screen)
3052 && XFT_DATA(fBtal)) {
3053 result = XFT_DATA(fBtal);
3054 } else if (XFT_DATA(fItal)) {
3055 result = XFT_DATA(fItal);
3056 }
3057 }
3058 if (result != NULL) {
3059 ; /* skip the other tests */
3060 } else
3061 #endif
3062 #if OPT_ISO_COLORS
3063 if ((attr_flags & UNDERLINE)
3064 && !screen->colorULMode
3065 && screen->italicULMode
3066 && XFT_DATA(fItal)) {
3067 result = XFT_DATA(fItal);
3068 *did_ul = True;
3069 } else
3070 #endif
3071 if ((attr_flags & BOLDATTR(screen))
3072 && UseBoldFont(screen)
3073 && XFT_DATA(fBold)) {
3074 result = XFT_DATA(fBold);
3075 } else {
3076 result = XFT_DATA(fNorm);
3077 }
3078 return result;
3079 }
3080
3081 #if OPT_RENDERWIDE
3082 #define pickXftData(width, nf, wf) (((width == 2) && ((wf) != NULL) && XftFp(wf) != NULL) ? (wf) : (nf))
3083 #define pickXftFont(width, nf, wf) (((width == 2) && ((wf) != NULL)) ? (wf) : (nf))
3084 #else
3085 #define pickXftData(width, nf, wf) (nf)
3086 #define pickXftFont(width, nf, wf) (nf)
3087 #endif
3088
3089 /*
3090 * fontconfig/Xft combination prior to 2.2 has a problem with
3091 * CJK truetype 'double-width' (bi-width/monospace) fonts leading
3092 * to the 's p a c e d o u t' rendering. Consequently, we can't
3093 * rely on XftDrawString8/16 when one of those fonts is used.
3094 * Instead, we need to roll out our own using XftDrawCharSpec.
3095 * A patch in the same spirit (but in a rather different form)
3096 * was applied to gnome vte and gtk2 port of vim.
3097 * See http://bugzilla.mozilla.org/show_bug.cgi?id=196312
3098 */
3099 static int
3100 xtermXftDrawString(XTermDraw * params,
3101 unsigned attr_flags,
3102 XftColor *color,
3103 XftFont *font,
3104 int x,
3105 int y,
3106 const IChar *text,
3107 Cardinal len,
3108 Bool really)
3109 {
3110 TScreen *screen = TScreenOf(params->xw);
3111 int ncells = 0;
3112
3113 (void) attr_flags;
3114 if (len != 0) {
3115 #if OPT_RENDERWIDE
3116 XftCharSpec *sbuf;
3117 XTermXftFonts *wdata = getWideXftFont(params, attr_flags);
3118 XftFont *wfont = XftFp(wdata);
3119 Cardinal src, dst;
3120 XftFont *lastFont = 0;
3121 XftFont *currFont = 0;
3122 Cardinal start = 0;
3123 int charWidth;
3124 int fwidth = FontWidth(screen);
3125 #if OPT_DEC_CHRSET
3126 Boolean forceDbl = CSET_DOUBLE(params->real_chrset);
3127 #else
3128 Boolean forceDbl = False;
3129 #endif
3130
3131 BumpTypedBuffer(XftCharSpec, 2 * len);
3132 sbuf = BfBuf(XftCharSpec);
3133
3134 for (src = dst = 0; src < len; src++) {
3135 FcChar32 wc = *text++;
3136
3137 charWidth = XtermCellWidth(params->xw, (wchar_t) wc);
3138 if (charWidth < 0)
3139 continue;
3140
3141 sbuf[dst].ucs4 = wc;
3142 sbuf[dst].x = (short) (x + fwidth * ncells);
3143 sbuf[dst].y = (short) (y);
3144
3145 currFont = pickXftFont(charWidth, font, wfont);
3146 ncells += charWidth;
3147
3148 if (lastFont != currFont) {
3149 if ((lastFont != 0) && really) {
3150 XftDrawCharSpec(screen->renderDraw,
3151 color,
3152 lastFont,
3153 sbuf + start,
3154 (int) (dst - start));
3155 }
3156 start = dst;
3157 lastFont = currFont;
3158 }
3159 ++dst;
3160
3161 if (forceDbl && charWidth < 2) {
3162 sbuf[dst].ucs4 = ' ';
3163 sbuf[dst].x = (short) (x + fwidth * ncells);
3164 sbuf[dst].y = (short) (y);
3165 ++dst;
3166 ncells += charWidth;
3167 }
3168 }
3169 if ((dst != start) && really) {
3170 XftDrawCharSpec(screen->renderDraw,
3171 color,
3172 lastFont,
3173 sbuf + start,
3174 (int) (dst - start));
3175 }
3176 #else /* !OPT_RENDERWIDE */
3177 if (really) {
3178 XftChar8 *buffer;
3179 int dst;
3180
3181 BumpTypedBuffer(XftChar8, len);
3182 buffer = BfBuf(XftChar8);
3183
3184 for (dst = 0; dst < (int) len; ++dst)
3185 buffer[dst] = CharOf(text[dst]);
3186
3187 XftDrawString8(screen->renderDraw,
3188 color,
3189 font,
3190 x, y, buffer, (int) len);
3191 }
3192 ncells = (int) len;
3193 #endif
3194 xtermNeedSwap(params->xw, 1);
3195 }
3196 return ncells;
3197 }
3198 #define xtermXftWidth(params, attr_flags, color, font, x, y, chars, len) \
3199 xtermXftDrawString(params, attr_flags, color, font, x, y, chars, len, False)
3200 #endif /* OPT_RENDERFONT */
3201
3202 #if OPT_WIDE_CHARS
3203 /*
3204 * Map characters commonly "fixed" by groff back to their ASCII equivalents.
3205 * Also map other useful equivalents.
3206 */
3207 unsigned
3208 AsciiEquivs(unsigned ch)
3209 {
3210 switch (ch) {
3211 case 0x2010: /* groff "-" */
3212 case 0x2011:
3213 case 0x2012:
3214 case 0x2013:
3215 case 0x2014:
3216 case 0x2015:
3217 case 0x2212: /* groff "\-" */
3218 ch = '-';
3219 break;
3220 case 0x2018: /* groff "`" */
3221 ch = '`';
3222 break;
3223 case 0x2019: /* groff ' */
3224 ch = '\'';
3225 break;
3226 case 0x201C: /* groff lq */
3227 case 0x201D: /* groff rq */
3228 ch = '"';
3229 break;
3230 case 0x2329: /* groff ".URL" */
3231 ch = '<';
3232 break;
3233 case 0x232a: /* groff ".URL" */
3234 ch = '>';
3235 break;
3236 default:
3237 if (ch >= 0xff01 && ch <= 0xff5e) {
3238 /* "Fullwidth" codes (actually double-width) */
3239 ch -= 0xff00;
3240 ch += ANSI_SPA;
3241 break;
3242 }
3243 }
3244 return ch;
3245 }
3246
3247 /*
3248 * Actually this should be called "groff_workaround()" - for the places where
3249 * groff stomps on compatibility. Still, if enough people get used to it,
3250 * this might someday become a quasi-standard.
3251 */
3252 #if OPT_BOX_CHARS
3253 static int
3254 ucs_workaround(XTermDraw * params,
3255 unsigned ch,
3256 GC gc,
3257 int x,
3258 int y)
3259 {
3260 TScreen *screen = TScreenOf(params->xw);
3261 int fixed = False;
3262
3263 if (screen->wide_chars && screen->utf8_mode && ch > 256) {
3264 IChar eqv = (IChar) AsciiEquivs(ch);
3265
3266 if (eqv != (IChar) ch) {
3267 int width = CharWidth(screen, ch);
3268
3269 do {
3270 drawXtermText(params,
3271 gc,
3272 x,
3273 y,
3274 &eqv,
3275 1);
3276 x += FontWidth(screen);
3277 eqv = BAD_ASCII;
3278 } while (width-- > 1);
3279
3280 fixed = True;
3281 } else if (ch == HIDDEN_CHAR) {
3282 fixed = True;
3283 }
3284 }
3285 return fixed;
3286 }
3287 #endif /* OPT_BOX_CHARS */
3288 #endif /* OPT_WIDE_CHARS */
3289
3290 /*
3291 * Use this when the characters will not fill the cell area properly. Fill the
3292 * area where we'll write the characters, otherwise we'll get gaps between
3293 * them, e.g., in the original background color.
3294 *
3295 * The cursor is a special case, because the XFillRectangle call only uses the
3296 * foreground, while we've set the cursor color in the background. So we need
3297 * a special GC for that.
3298 */
3299 static void
3300 xtermFillCells(XTermDraw * params,
3301 GC gc,
3302 int x,
3303 int y,
3304 Cardinal len)
3305 {
3306 TScreen *screen = TScreenOf(params->xw);
3307 VTwin *currentWin = WhichVWin(screen);
3308
3309 if (!(params->draw_flags & NOBACKGROUND)) {
3310 CgsEnum srcId = getCgsId(params->xw, currentWin, gc);
3311 CgsEnum dstId = gcMAX;
3312 Pixel fg = getCgsFore(params->xw, currentWin, gc);
3313 Pixel bg = getCgsBack(params->xw, currentWin, gc);
3314
3315 switch (srcId) {
3316 case gcVTcursNormal:
3317 case gcVTcursReverse:
3318 dstId = gcVTcursOutline;
3319 break;
3320 case gcVTcursFilled:
3321 case gcVTcursOutline:
3322 /* FIXME */
3323 break;
3324 case gcNorm:
3325 dstId = gcNormReverse;
3326 break;
3327 case gcNormReverse:
3328 dstId = gcNorm;
3329 break;
3330 case gcBold:
3331 dstId = gcBoldReverse;
3332 break;
3333 case gcBoldReverse:
3334 dstId = gcBold;
3335 break;
3336 case gcBorder:
3337 case gcFiller:
3338 dstId = srcId;
3339 break;
3340 #if OPT_BOX_CHARS
3341 case gcLine:
3342 case gcDots:
3343 /* FIXME */
3344 break;
3345 #endif
3346 #if OPT_DEC_CHRSET
3347 case gcCNorm:
3348 case gcCBold:
3349 /* FIXME */
3350 break;
3351 #endif
3352 #if OPT_WIDE_CHARS
3353 case gcWide:
3354 dstId = gcWideReverse;
3355 break;
3356 case gcWBold:
3357 dstId = gcBoldReverse;
3358 break;
3359 case gcWideReverse:
3360 case gcWBoldReverse:
3361 /* FIXME */
3362 break;
3363 #endif
3364 #if OPT_TEK4014
3365 case gcTKcurs:
3366 /* FIXME */
3367 break;
3368 #endif
3369 case gcMAX:
3370 break;
3371 }
3372
3373 if (dstId != gcMAX) {
3374 setCgsFore(params->xw, currentWin, dstId, bg);
3375 setCgsBack(params->xw, currentWin, dstId, fg);
3376
3377 XFillRectangle(screen->display, VDrawable(screen),
3378 getCgsGC(params->xw, currentWin, dstId),
3379 x, y,
3380 len * (Cardinal) FontWidth(screen),
3381 (unsigned) FontHeight(screen));
3382 }
3383 }
3384 }
3385
3386 #if OPT_TRACE
3387 static void
3388 xtermSetClipRectangles(Display *dpy,
3389 GC gc,
3390 int x,
3391 int y,
3392 XRectangle * rp,
3393 Cardinal nr,
3394 int order)
3395 {
3396 #if 0
3397 TScreen *screen = TScreenOf(term);
3398 Drawable draw = VDrawable(screen);
3399
3400 XSetClipMask(dpy, gc, None);
3401 XDrawRectangle(screen->display, draw, gc,
3402 x + rp->x - 1,
3403 y + rp->y - 1,
3404 rp->width,
3405 rp->height);
3406 #endif
3407
3408 XSetClipRectangles(dpy, gc,
3409 x, y, rp, (int) nr, order);
3410 TRACE(("clipping @(%3d,%3d) (%3d,%3d)..(%3d,%3d)\n",
3411 y, x,
3412 rp->y, rp->x, rp->height, rp->width));
3413 }
3414
3415 #else
3416 #define xtermSetClipRectangles(dpy, gc, x, y, rp, nr, order) \
3417 XSetClipRectangles(dpy, gc, x, y, rp, (int) nr, order)
3418 #endif
3419
3420 #if OPT_CLIP_BOLD
3421 /*
3422 * This special case is a couple of percent slower, but avoids a lot of pixel
3423 * trash in rxcurses' hanoi.cmd demo (e.g., 10x20 font).
3424 */
3425 #define beginClipping(screen,gc,pwidth,plength) \
3426 if (pwidth > 2) { \
3427 if (screen->use_clipping) { \
3428 XRectangle clip; \
3429 int clip_x = x; \
3430 int clip_y = y - FontHeight(screen) + FontDescent(screen); \
3431 clip.x = 0; \
3432 clip.y = 0; \
3433 clip.height = (unsigned short) FontHeight(screen); \
3434 clip.width = (unsigned short) ((pwidth) * (plength)); \
3435 xtermSetClipRectangles(screen->display, gc, \
3436 clip_x, clip_y, \
3437 &clip, 1, Unsorted); \
3438 } else if (screen->use_border_clipping) { \
3439 XRectangle clip; \
3440 clip.x = 0; \
3441 clip.y = 0; \
3442 clip.height = (unsigned short) Height(screen); \
3443 clip.width = (unsigned short) Width(screen); \
3444 xtermSetClipRectangles(screen->display, gc, \
3445 0, 0, \
3446 &clip, 1, Unsorted); \
3447 } \
3448 }
3449 #define endClipping(screen,gc) \
3450 XSetClipMask(screen->display, gc, None)
3451 #else
3452 #define beginClipping(screen,gc,pwidth,plength) /* nothing */
3453 #define endClipping(screen,gc) /* nothing */
3454 #endif /* OPT_CLIP_BOLD */
3455
3456 #if OPT_RENDERFONT
3457 static int
3458 drawClippedXftString(XTermDraw * params,
3459 unsigned attr_flags,
3460 XftFont *font,
3461 XftColor *fg_color,
3462 int x,
3463 int y,
3464 const IChar *text,
3465 Cardinal len)
3466 {
3467 int ncells = xtermXftWidth(params, attr_flags,
3468 fg_color,
3469 font, x, y,
3470 text,
3471 len);
3472 TScreen *screen = TScreenOf(params->xw);
3473 int fontHigh = FontHeight(screen);
3474 int fontWide = FontWidth(screen);
3475
3476 if (fontWide > 2) {
3477 int plength = (ncells ? ncells : 1);
3478 Boolean halfHigh = False;
3479 #if OPT_DEC_CHRSET
3480 Boolean halfWide = False;
3481
3482 switch (params->real_chrset) {
3483 case CSET_SWL:
3484 break;
3485 case CSET_DWL:
3486 halfWide = True;
3487 break;
3488 case CSET_DHL_TOP:
3489 halfHigh = True;
3490 halfWide = True;
3491 break;
3492 case CSET_DHL_BOT:
3493 halfHigh = True;
3494 halfWide = True;
3495 break;
3496 }
3497 if (CSET_DOUBLE(params->real_chrset)) {
3498 fontHigh = font->height;
3499 fontWide = font->max_advance_width;
3500 /* check if this is really a double-height font */
3501 if (halfHigh) {
3502 int wantHigh = (int) (FontHeight(screen) * 1.8);
3503 halfHigh = (fontHigh >= wantHigh);
3504 TRACE(("comparing fontHigh %d/%d vs %d:"
3505 " double-height %s for %s\n",
3506 fontHigh, FontHeight(screen),
3507 wantHigh, BtoS(halfHigh),
3508 visibleDblChrset(params->real_chrset)));
3509 }
3510 fontHigh = (halfHigh
3511 ? (2 * FontHeight(screen))
3512 : FontHeight(screen));
3513 /* check if this is really a double-width font */
3514 if (halfWide) {
3515 int wantWide = (int) (FontWidth(screen) * 1.8);
3516 halfWide = (fontWide >= wantWide);
3517 TRACE(("comparing fontWide %d/%d vs %d:"
3518 " double-width %s for %s\n",
3519 fontWide, FontWidth(screen),
3520 wantWide, BtoS(halfWide),
3521 visibleDblChrset(params->real_chrset)));
3522 }
3523 fontWide = (halfWide
3524 ? (2 * FontWidth(screen))
3525 : FontWidth(screen));
3526 }
3527 #endif
3528 if (screen->use_clipping || halfHigh) {
3529 XRectangle clip;
3530 double adds = ((double) screen->scale_height - 1.0f) * fontHigh;
3531 int height = dimRound(adds + fontHigh);
3532 int descnt = dimRound(adds / 2.0) + FontDescent(screen);
3533 int clip_x = (x);
3534 int clip_y = (y) - height + descnt;
3535
3536 clip.x = 0;
3537 clip.y = 0;
3538 clip.height = (Dimension) height;
3539 clip.width = (Dimension) (fontWide * (Dimension) (plength));
3540
3541 #if OPT_DEC_CHRSET
3542 if (halfHigh) {
3543 int adjust;
3544
3545 clip.height = (unsigned short) FontHeight(screen);
3546 clip_y += descnt;
3547 if (params->real_chrset == CSET_DHL_BOT) {
3548 y -= clip.height;
3549 }
3550 adjust = ((clip_y - OriginY(screen)) % FontHeight(screen));
3551 if (adjust) {
3552 if (adjust > FontHeight(screen) / 2)
3553 adjust -= FontHeight(screen);
3554 clip_y -= adjust;
3555 }
3556 }
3557 #endif
3558 XftDrawSetClipRectangles(screen->renderDraw,
3559 clip_x, clip_y,
3560 &clip, 1);
3561 } else if (screen->use_border_clipping) {
3562 XRectangle clip;
3563
3564 clip.x = (Position) OriginX(screen);
3565 clip.y = (Position) OriginY(screen);
3566 clip.height = (Dimension) Height(screen);
3567 clip.width = (Dimension) Width(screen);
3568
3569 XftDrawSetClipRectangles(screen->renderDraw,
3570 0, 0,
3571 &clip, 1);
3572 }
3573 }
3574
3575 xtermXftDrawString(params, attr_flags,
3576 fg_color,
3577 font, x, y + ScaleShift(screen),
3578 text,
3579 len,
3580 True);
3581 XftDrawSetClip(screen->renderDraw, 0);
3582 return ncells;
3583 }
3584 #endif
3585
3586 #ifndef NO_ACTIVE_ICON
3587 #define WhichVFontData(screen,name) \
3588 (IsIcon(screen) ? getIconicFont(screen) \
3589 : GetNormalFont(screen, name))
3590 #else
3591 #define WhichVFontData(screen,name) \
3592 GetNormalFont(screen, name)
3593 #endif
3594
3595 static void
3596 drawUnderline(XtermWidget xw,
3597 GC gc,
3598 unsigned attr_flags,
3599 unsigned underline_len,
3600 int font_width,
3601 int x,
3602 int y,
3603 Bool did_ul)
3604 {
3605 TScreen *screen = TScreenOf(xw);
3606
3607 if (screen->underline && !did_ul) {
3608 int repeat = 0;
3609 int descent = FontDescent(screen);
3610 int length = x + (int) underline_len * font_width - 1;
3611
3612 #if OPT_WIDE_ATTRS
3613 if ((attr_flags & ATR_STRIKEOUT)) {
3614 int where = y - ((3 * FontAscent(screen)) / 8);
3615 XDrawLine(screen->display, VDrawable(screen), gc,
3616 x, where,
3617 length,
3618 where);
3619 }
3620 if ((attr_flags & ATR_DBL_UNDER)) {
3621 repeat = 2;
3622 } else
3623 #endif
3624 if ((attr_flags & UNDERLINE)) {
3625 repeat = 1;
3626 }
3627 while (repeat-- > 0) {
3628 if (descent-- > 1)
3629 y++;
3630 XDrawLine(screen->display, VDrawable(screen), gc,
3631 x, y,
3632 length,
3633 y);
3634 }
3635 }
3636 }
3637
3638 #if OPT_WIDE_ATTRS
3639 /*
3640 * As a special case, we are currently allowing italic fonts to be inexact
3641 * matches for the normal font's size. That introduces a problem: either the
3642 * ascent or descent may be shorter, leaving a gap that has to be filled in.
3643 * Or they may be larger, requiring clipping. Check for both cases.
3644 */
3645 static int
3646 fixupItalics(XTermDraw * params,
3647 GC gc,
3648 XTermFonts * curFont,
3649 int y, int x,
3650 int font_width,
3651 Cardinal len)
3652 {
3653 TScreen *screen = TScreenOf(params->xw);
3654 VTwin *cgsWin = WhichVWin(screen);
3655 XFontStruct *realFp = curFont->fs;
3656 XFontStruct *thisFp = getCgsFont(params->xw, cgsWin, gc)->fs;
3657 int need_clipping = 0;
3658 int need_filling = 0;
3659
3660 if (thisFp->ascent > realFp->ascent)
3661 need_clipping = 1;
3662 else if (thisFp->ascent < realFp->ascent)
3663 need_filling = 1;
3664
3665 if (thisFp->descent > realFp->descent)
3666 need_clipping = 1;
3667 else if (thisFp->descent < realFp->descent)
3668 need_filling = 1;
3669
3670 if (need_clipping) {
3671 beginClipping(screen, gc, font_width, (int) len);
3672 }
3673 if (need_filling) {
3674 xtermFillCells(params,
3675 gc,
3676 x,
3677 y - realFp->ascent,
3678 len);
3679 }
3680 return need_clipping;
3681 }
3682 #endif
3683
3684 #if OPT_DEC_CHRSET
3685 static int
3686 fakeDoubleChars(XTermDraw * params,
3687 GC gc,
3688 int y,
3689 int x,
3690 const IChar *text,
3691 Cardinal len)
3692 {
3693 unsigned need = 2 * len;
3694 IChar *temp = TypeMallocN(IChar, need);
3695
3696 if (temp != 0) {
3697 unsigned n = 0;
3698 XTermDraw recur = *params;
3699
3700 recur.this_chrset = CSET_SWL;
3701
3702 while (len--) {
3703 temp[n++] = *text++;
3704 temp[n++] = ' ';
3705 }
3706 x = drawXtermText(&recur,
3707 gc,
3708 x, y,
3709 temp,
3710 n);
3711 free(temp);
3712 }
3713 return x;
3714 }
3715 #endif /* OPT_DEC_CHRSET */
3716
3717 #define SetMissing(tag) \
3718 TRACE(("%s %s: missing %d %04X\n", __FILE__, tag, missing, ch)); \
3719 missing = 1
3720
3721 #define MaxImageString 255
3722
3723 /*
3724 * Draws text with the specified combination of bold/underline. The return
3725 * value is the updated x position.
3726 */
3727 int
3728 drawXtermText(XTermDraw * params,
3729 GC gc,
3730 int start_x,
3731 int start_y,
3732 const IChar *text,
3733 Cardinal len)
3734 {
3735 XTermDraw recur = *params;
3736 TScreen *screen = TScreenOf(recur.xw);
3737 int x = start_x;
3738 int y = start_y;
3739 int y_shift = ScaleShift(screen);
3740 Cardinal real_length = len;
3741 Cardinal underline_len = 0;
3742 /* Intended width of the font to draw (as opposed to the actual width of
3743 the X font, and the width of the default font) */
3744 int font_width = (((recur.draw_flags & DOUBLEWFONT) ? 2 : 1)
3745 * screen->fnt_wide);
3746 Bool did_ul = False;
3747 XTermFonts *curFont;
3748
3749 #if OPT_WIDE_ATTRS
3750 int need_clipping = 0;
3751 #endif
3752
3753 #if OPT_WIDE_CHARS
3754 Bool need_wide;
3755 #endif
3756
3757 #if OPT_WIDE_CHARS
3758 if (text == 0)
3759 return 0;
3760 #endif
3761 TRACE(("DRAWTEXT%c[%4d,%4d] (%d)%3d:%s\n",
3762 screen->cursor_state == OFF ? ' ' : '*',
3763 y, x, recur.this_chrset, len,
3764 visibleIChars(text, len)));
3765
3766 #if OPT_DEC_CHRSET
3767 if (CSET_DOUBLE(recur.this_chrset)) {
3768 /* We could try drawing double-size characters in the icon, but
3769 * given that the icon font is usually nil or nil2, there
3770 * doesn't seem to be much point.
3771 */
3772 int inx = 0;
3773 GC gc2;
3774
3775 #if OPT_RENDERFONT
3776 if (UsingRenderFont(recur.xw)) {
3777 if (!IsIcon(screen) && screen->font_doublesize) {
3778 TRACE(("drawing %s\n", visibleDblChrset((unsigned) recur.this_chrset)));
3779 recur.real_chrset = recur.this_chrset;
3780 recur.this_chrset = CSET_SWL;
3781 x = drawXtermText(&recur,
3782 gc,
3783 x, y,
3784 text,
3785 len);
3786 x += ((int) len) * FontWidth(screen);
3787 } else {
3788 x = fakeDoubleChars(&recur,
3789 gc, y, x,
3790 text, len);
3791 }
3792 } else
3793 #endif
3794 if ((!IsIcon(screen) && screen->font_doublesize)
3795 && (gc2 = xterm_DoubleGC(&recur, gc, &inx)) != 0) {
3796 /* draw actual double-sized characters */
3797 XFontStruct *fs = getDoubleFont(screen, inx)->fs;
3798 XRectangle rect, *rp = ▭
3799 Cardinal nr = 1;
3800
3801 font_width *= 2;
3802 recur.draw_flags |= DOUBLEWFONT;
3803
3804 rect.x = 0;
3805 rect.y = 0;
3806 rect.width = (unsigned short) ((int) len * font_width);
3807 rect.height = (unsigned short) (FontHeight(screen));
3808
3809 TRACE(("drawing %s\n", visibleDblChrset((unsigned) recur.this_chrset)));
3810 switch (recur.this_chrset) {
3811 case CSET_DHL_TOP:
3812 rect.y = (short) -(fs->ascent / 2);
3813 y -= rect.y;
3814 recur.draw_flags |= DOUBLEHFONT;
3815 break;
3816 case CSET_DHL_BOT:
3817 rect.y = (short) (rect.height - (fs->ascent / 2));
3818 y -= rect.y;
3819 recur.draw_flags |= DOUBLEHFONT;
3820 break;
3821 case CSET_DWL:
3822 break;
3823 default:
3824 nr = 0;
3825 break;
3826 }
3827
3828 if (nr) {
3829 xtermSetClipRectangles(screen->display, gc2,
3830 x, y, rp, nr, YXBanded);
3831 xtermFillCells(&recur, gc, x, y + rect.y, len * 2);
3832 } else {
3833 XSetClipMask(screen->display, gc2, None);
3834 }
3835
3836 /* Call ourselves recursively with the new gc */
3837
3838 /*
3839 * If we're trying to use proportional font, or if the
3840 * font server didn't give us what we asked for wrt
3841 * width, position each character independently.
3842 */
3843 if (screen->fnt_prop
3844 || (fs->min_bounds.width != fs->max_bounds.width)
3845 || (fs->min_bounds.width != 2 * FontWidth(screen))) {
3846 /* It is hard to fall-through to the main
3847 branch: in a lot of places the check
3848 for the cached font info is for
3849 normal/bold fonts only. */
3850 XTermDraw param2 = recur;
3851 param2.this_chrset = CSET_SWL;
3852 while (len--) {
3853 x = drawXtermText(¶m2,
3854 gc2,
3855 x, y,
3856 text++,
3857 1);
3858 x += FontWidth(screen);
3859 }
3860 } else {
3861 XTermDraw param2 = recur;
3862 param2.this_chrset = CSET_SWL;
3863 x = drawXtermText(¶m2,
3864 gc2,
3865 x, y,
3866 text,
3867 len);
3868 x += (int) len *FontWidth(screen);
3869 }
3870
3871 } else { /* simulate double-sized characters */
3872 x = fakeDoubleChars(&recur,
3873 gc, y, x,
3874 text, len);
3875 }
3876 TRACE(("DrewText [%4d,%4d]\n", y, x));
3877 return x;
3878 }
3879 #endif
3880 #if OPT_RENDERFONT
3881 if (UsingRenderFont(recur.xw)) {
3882 VTwin *currentWin = WhichVWin(screen);
3883 Display *dpy = screen->display;
3884 XTermXftFonts *ndata;
3885 XGCValues values;
3886 #if OPT_WIDE_CHARS
3887 XTermXftFonts *ndata0;
3888 #endif
3889 #if OPT_RENDERWIDE
3890 XTermXftFonts *wdata;
3891 XTermXftFonts *wdata0;
3892 #endif
3893
3894 #if OPT_DEC_CHRSET
3895 /*
3896 * If this is a VT100-style double-width font, ensure that everything
3897 * is printed using two-columns per character.
3898 */
3899 Boolean forceDbl = CSET_DOUBLE(recur.real_chrset);
3900 #else
3901 Boolean forceDbl = False;
3902 #endif
3903
3904 (void) forceDbl;
3905 /*
3906 * Defer creating the drawable until we need it.
3907 */
3908 if (!screen->renderDraw) {
3909 int scr;
3910 Drawable draw = VDrawable(screen);
3911 Visual *visual;
3912
3913 scr = DefaultScreen(dpy);
3914 visual = DefaultVisual(dpy, scr);
3915 screen->renderDraw = XftDrawCreate(dpy, draw, visual,
3916 DefaultColormap(dpy, scr));
3917 }
3918
3919 /*
3920 * ndata0/wdata0 provide fallback to non-bolded Xft font if a glyph is
3921 * not found in the bold version.
3922 */
3923 #define IS_BOLD (recur.attr_flags & BOLDATTR(screen))
3924 #define NOT_BOLD (recur.attr_flags & ~BOLDATTR(screen))
3925 ndata = getNormXftFont(&recur, recur.attr_flags, &did_ul);
3926 #if OPT_WIDE_CHARS
3927 ndata0 = IS_BOLD ? getNormXftFont(&recur, NOT_BOLD, &did_ul) : ndata;
3928 #endif
3929 #if OPT_RENDERWIDE
3930 wdata = getWideXftFont(&recur, recur.attr_flags);
3931 wdata0 = IS_BOLD ? getWideXftFont(&recur, NOT_BOLD) : wdata;
3932 #endif
3933
3934 #define GET_XFT_FG() getXftColor(recur.xw, values.foreground)
3935 #define GET_XFT_BG() getXftColor(recur.xw, values.background)
3936
3937 values.foreground = getCgsFore(recur.xw, currentWin, gc);
3938 values.background = getCgsBack(recur.xw, currentWin, gc);
3939
3940 if (!(recur.draw_flags & NOBACKGROUND)) {
3941 XftColor *bg_color = GET_XFT_BG();
3942 int ncells = xtermXftWidth(&recur, recur.attr_flags,
3943 bg_color,
3944 XftFp(ndata), x, y,
3945 text,
3946 len);
3947 XftDrawRect(screen->renderDraw,
3948 bg_color,
3949 x, y,
3950 (unsigned) (ncells * FontWidth(screen)),
3951 (unsigned) FontHeight(screen));
3952 }
3953
3954 y += XftFp(ndata)->ascent;
3955 #if OPT_BOX_CHARS
3956 {
3957 /* adding code to substitute simulated line-drawing characters */
3958 int last, first = 0;
3959 int curX = x;
3960
3961 for (last = 0; last < (int) len; last++) {
3962 Boolean replace = False;
3963 Boolean missing = False;
3964 unsigned ch = (unsigned) text[last];
3965 int filler = 0;
3966 #if OPT_WIDE_CHARS
3967 int needed = forceDbl ? 2 : CharWidth(screen, ch);
3968 XTermXftFonts *currData = pickXftData(needed, ndata, wdata);
3969 XftFont *tempFont = 0;
3970 #define CURR_TEMP (tempFont ? tempFont : XftFp(currData))
3971
3972 if (xtermIsDecGraphic(ch) || ch == 0) {
3973 /*
3974 * Xft generally does not have the line-drawing characters
3975 * in cells 0-31. Assume this (we cannot inspect the
3976 * picture easily...), and attempt to fill in from real
3977 * line-drawing character in the font at the Unicode
3978 * position. Failing that, use our own box-characters.
3979 */
3980 if (screen->force_box_chars
3981 || screen->broken_box_chars
3982 || xtermXftMissing(recur.xw,
3983 currData, 0,
3984 XftFp(currData),
3985 dec2ucs(screen, ch))) {
3986 SetMissing("case 1");
3987 } else {
3988 ch = dec2ucs(screen, ch);
3989 replace = True;
3990 }
3991 } else if (ch >= 256) {
3992 /*
3993 * If we're reading UTF-8 from the client, we may have a
3994 * line-drawing character. Translate it back to our
3995 * box-code if Xft tells us that the glyph is missing.
3996 */
3997 if_OPT_WIDE_CHARS(screen, {
3998 unsigned part = ucs2dec(screen, ch);
3999 if (xtermIsDecGraphic(part)) {
4000 if (screen->force_box_chars
4001 || screen->broken_box_chars) {
4002 SetMissing("case 2");
4003 ch = part;
4004 }
4005 }
4006 if (!missing && xtermXftMissing(recur.xw,
4007 currData, 0,
4008 XftFp(currData), ch)) {
4009 int found = findXftGlyph(recur.xw, currData, ch);
4010 XftFont *test;
4011 if (found >= 0) {
4012 test = XftFpN(currData, found);
4013 } else {
4014 test = pickXftFont(needed,
4015 XftFp(ndata0),
4016 XftFp(wdata0));
4017 }
4018 if (!xtermXftMissing(recur.xw,
4019 currData, found,
4020 test, ch)) {
4021 tempFont = test;
4022 replace = True;
4023 filler = 0;
4024 } else if ((part = AsciiEquivs(ch)) != ch) {
4025 filler = needed - 1;
4026 ch = part;
4027 replace = True;
4028 } else if (ch != HIDDEN_CHAR) {
4029 SetMissing("case 3");
4030 }
4031 }
4032 });
4033 }
4034 #else
4035 XTermXftFonts *currData = ndata;
4036 #define CURR_TEMP XftFp(currData)
4037 if (xtermIsDecGraphic(ch)) {
4038 /*
4039 * Xft generally does not have the line-drawing characters
4040 * in cells 1-31. Check for this, and attempt to fill in
4041 * from real line-drawing character in the font at the
4042 * Unicode position. Failing that, use our own
4043 * box-characters.
4044 */
4045 if (xtermXftMissing(recur.xw,
4046 currData, 0,
4047 XftFp(currData), ch)) {
4048 SetMissing("case 4");
4049 }
4050 }
4051 #endif
4052
4053 /*
4054 * If we now have one of our box-codes, draw it directly.
4055 */
4056 if (missing || replace) {
4057 /* line drawing character time */
4058 if (last > first) {
4059 int nc = drawClippedXftString(&recur,
4060 recur.attr_flags,
4061 XftFp(currData),
4062 GET_XFT_FG(),
4063 curX,
4064 y,
4065 text + first,
4066 (Cardinal) (last - first));
4067 curX += nc * FontWidth(screen);
4068 underline_len += (Cardinal) nc;
4069 }
4070 if (missing) {
4071 Dimension old_wide = screen->fnt_wide;
4072 Dimension old_high = screen->fnt_high;
4073 screen->fnt_wide = (Dimension) FontWidth(screen);
4074 screen->fnt_high = (Dimension) FontHeight(screen);
4075
4076 xtermDrawBoxChar(&recur, ch,
4077 gc,
4078 curX,
4079 y - FontAscent(screen),
4080 1,
4081 True);
4082 curX += FontWidth(screen);
4083 underline_len += 1;
4084 screen->fnt_wide = old_wide;
4085 screen->fnt_high = old_high;
4086 } else {
4087 IChar ch2 = (IChar) ch;
4088 int nc = drawClippedXftString(&recur,
4089 recur.attr_flags,
4090 CURR_TEMP,
4091 GET_XFT_FG(),
4092 curX,
4093 y,
4094 &ch2,
4095 1);
4096 curX += nc * FontWidth(screen);
4097 underline_len += (Cardinal) nc;
4098 if (filler) {
4099 ch2 = ' ';
4100 nc = drawClippedXftString(&recur,
4101 recur.attr_flags,
4102 CURR_TEMP,
4103 GET_XFT_FG(),
4104 curX,
4105 y,
4106 &ch2,
4107 1);
4108 curX += nc * FontWidth(screen);
4109 underline_len += (Cardinal) nc;
4110 }
4111 }
4112 first = last + 1;
4113 }
4114 }
4115 if (last > first) {
4116 underline_len += (Cardinal)
4117 drawClippedXftString(&recur,
4118 recur.attr_flags,
4119 XftFp(ndata),
4120 GET_XFT_FG(),
4121 curX,
4122 y,
4123 text + first,
4124 (Cardinal) (last - first));
4125 }
4126 }
4127 #else
4128 {
4129 underline_len += (Cardinal)
4130 drawClippedXftString(&recur,
4131 recur.attr_flags,
4132 XftFp(ndata),
4133 GET_XFT_FG(),
4134 x,
4135 y,
4136 text,
4137 len);
4138 }
4139 #endif /* OPT_BOX_CHARS */
4140
4141 drawUnderline(recur.xw,
4142 gc,
4143 recur.attr_flags,
4144 underline_len,
4145 FontWidth(screen),
4146 x,
4147 y + y_shift,
4148 did_ul);
4149
4150 x += (int) len *FontWidth(screen);
4151
4152 return x;
4153 }
4154 #endif /* OPT_RENDERFONT */
4155 curFont = ((recur.attr_flags & BOLDATTR(screen))
4156 ? WhichVFontData(screen, fBold)
4157 : WhichVFontData(screen, fNorm));
4158 /*
4159 * If we're asked to display a proportional font, do this with a fixed
4160 * pitch. Yes, it's ugly. But we cannot distinguish the use of xterm
4161 * as a dumb terminal vs its use as in fullscreen programs such as vi.
4162 * Hint: do not try to use a proportional font in the icon.
4163 */
4164 if (!IsIcon(screen) && !(recur.draw_flags & CHARBYCHAR) && screen->fnt_prop) {
4165 int adj, width;
4166
4167 while (len--) {
4168 int cells = WideCells(*text);
4169 #if OPT_BOX_CHARS
4170 #if OPT_WIDE_CHARS
4171 if (*text == HIDDEN_CHAR) {
4172 ++text;
4173 continue;
4174 } else
4175 #endif
4176 if (IsXtermMissingChar(screen, *text, curFont)) {
4177 adj = 0;
4178 } else
4179 #endif
4180 {
4181 if_WIDE_OR_NARROW(screen, {
4182 XChar2b temp[1];
4183 temp[0].byte2 = LO_BYTE(*text);
4184 temp[0].byte1 = HI_BYTE(*text);
4185 width = XTextWidth16(curFont->fs, temp, 1);
4186 }
4187 , {
4188 char temp[1];
4189 temp[0] = (char) LO_BYTE(*text);
4190 width = XTextWidth(curFont->fs, temp, 1);
4191 });
4192 adj = (FontWidth(screen) - width) / 2;
4193 if (adj < 0)
4194 adj = 0;
4195 }
4196 xtermFillCells(&recur, gc, x, y, (Cardinal) cells);
4197 recur.draw_flags |= (NOBACKGROUND | CHARBYCHAR);
4198 x = drawXtermText(&recur,
4199 gc, x + adj, y,
4200 text++, 1) - adj;
4201 }
4202
4203 return x;
4204 }
4205 #if OPT_BOX_CHARS
4206 /*
4207 * Draw some substitutions, if needed. The font may not include the
4208 * line-drawing set, or it may be incomplete (in which case we'll draw an
4209 * empty space via xtermDrawBoxChar), or we may be told to force our
4210 * line-drawing.
4211 *
4212 * The empty space is a special case which can be overridden with the
4213 * showMissingGlyphs resource to produce an outline. Not all fonts in
4214 * "modern" (sic) X provide an empty space; some use a thick outline or
4215 * something like the replacement character. If you would rather not see
4216 * that, you can set assumeAllChars.
4217 */
4218 if (!IsIcon(screen)
4219 && !(recur.draw_flags & NOTRANSLATION)
4220 && (!screen->fnt_boxes
4221 || (FontIsIncomplete(curFont) && !screen->assume_all_chars)
4222 || recur.xw->work.force_wideFont
4223 || screen->force_box_chars)) {
4224 /*
4225 * Fill in missing box-characters. Find regions without missing
4226 * characters, and draw them calling ourselves recursively. Draw
4227 * missing characters via xtermDrawBoxChar().
4228 */
4229 int last, first = 0;
4230 Bool drewBoxes = False;
4231
4232 for (last = 0; last < (int) len; last++) {
4233 unsigned ch = (unsigned) text[last];
4234 Bool isMissing;
4235 int ch_width;
4236 #if OPT_WIDE_CHARS
4237
4238 if (ch == HIDDEN_CHAR) {
4239 if (last > first) {
4240 XTermDraw param2 = recur;
4241 param2.draw_flags |= NOTRANSLATION;
4242 x = drawXtermText(¶m2,
4243 gc,
4244 x, y,
4245 text + first,
4246 (unsigned) (last - first));
4247 }
4248 first = last + 1;
4249 drewBoxes = True;
4250 continue;
4251 }
4252 ch_width = CharWidth(screen, ch);
4253 isMissing =
4254 IsXtermMissingChar(screen, ch,
4255 ((recur.on_wide || ch_width > 1)
4256 && okFont(NormalWFont(screen)))
4257 ? WhichVFontData(screen, fWide)
4258 : curFont);
4259 #else
4260 isMissing = IsXtermMissingChar(screen, ch, curFont);
4261 ch_width = 1;
4262 #endif
4263 /*
4264 * If the character is not missing, but we're in wide-character
4265 * mode and the character happens to be a wide-character that
4266 * corresponds to the line-drawing set, allow the forceBoxChars
4267 * resource (or menu entry) to force it to display using our
4268 * tables.
4269 */
4270 if_OPT_WIDE_CHARS(screen, {
4271 if (!isMissing
4272 && TScreenOf(recur.xw)->force_box_chars) {
4273 if (ch > 255
4274 && ucs2dec(screen, ch) < 32) {
4275 ch = ucs2dec(screen, ch);
4276 isMissing = True;
4277 } else if (ch < 32) {
4278 isMissing = True;
4279 }
4280 }
4281 });
4282
4283 if (isMissing) {
4284 if (last > first) {
4285 XTermDraw param2 = recur;
4286 param2.draw_flags |= NOTRANSLATION;
4287 x = drawXtermText(&recur,
4288 gc,
4289 x, y,
4290 text + first,
4291 (unsigned) (last - first));
4292 }
4293 #if OPT_WIDE_CHARS
4294 if (ch_width <= 0 && ch < 32)
4295 ch_width = 1; /* special case for line-drawing */
4296 else if (ch_width < 0)
4297 ch_width = 1; /* special case for combining char */
4298 if (!ucs_workaround(&recur, ch, gc, x, y)) {
4299 xtermDrawBoxChar(&recur, ch, gc, x, y, ch_width, False);
4300 }
4301 #else
4302 xtermDrawBoxChar(&recur, ch, gc, x, y, ch_width, False);
4303 #endif
4304 x += (ch_width * FontWidth(screen));
4305 first = last + 1;
4306 drewBoxes = True;
4307 } else if (ch_width == 2
4308 && recur.xw->work.force_wideFont
4309 && !(recur.draw_flags & NOTRANSLATION)) {
4310 XTermDraw param2 = recur;
4311 param2.draw_flags |= NOTRANSLATION;
4312 /*
4313 * Not a "box" character, but a special case treated similarly.
4314 */
4315 (void) drawXtermText(¶m2,
4316 gc,
4317 x, y,
4318 text + first,
4319 (unsigned) (1 + last - first));
4320 x += (ch_width * FontWidth(screen));
4321 first = last + 1;
4322 drewBoxes = True;
4323 }
4324 }
4325 if (last <= first) {
4326 return x;
4327 }
4328 text += first;
4329 len = (Cardinal) (last - first);
4330 recur.draw_flags |= NOTRANSLATION;
4331 if (drewBoxes) {
4332 return drawXtermText(&recur,
4333 gc,
4334 x,
4335 y,
4336 text,
4337 len);
4338 }
4339 }
4340 #endif /* OPT_BOX_CHARS */
4341 /*
4342 * Behave as if the font has (maybe Unicode-replacements for) drawing
4343 * characters in the range 1-31 (either we were not asked to ignore them,
4344 * or the caller made sure that there is none).
4345 */
4346 #if OPT_WIDE_ATTRS
4347 #define AttrFlags() recur.attr_flags
4348 #define DrawFlags() recur.draw_flags
4349 #else
4350 #define AttrFlags() (recur.attr_flags & DRAWX_MASK)
4351 #define DrawFlags() (recur.draw_flags & (unsigned)~DRAWX_MASK)
4352 #endif
4353 TRACE(("drawtext%c[%4d,%4d] {%#x,%#x} (%d) %d:%s\n",
4354 screen->cursor_state == OFF ? ' ' : '*',
4355 y, x,
4356 AttrFlags(),
4357 DrawFlags(),
4358 recur.this_chrset, len,
4359 visibleIChars(text, len)));
4360 if (screen->scale_height != 1.0f) {
4361 xtermFillCells(&recur, gc, x, y, (Cardinal) len);
4362 }
4363 y += FontAscent(screen);
4364
4365 #if OPT_WIDE_CHARS
4366
4367 need_wide = False;
4368 if (screen->wide_chars || screen->unicode_font) {
4369 int src;
4370 for (src = 0; src < (int) len; src++) {
4371 IChar ch = text[src];
4372 if (ch > 0xff) {
4373 need_wide = True;
4374 break;
4375 }
4376 }
4377 }
4378
4379 if (need_wide) {
4380 XChar2b *buffer;
4381 Bool needWide = False;
4382 int src, dst;
4383 Bool useBoldFont;
4384 int ascent_adjust = 0;
4385
4386 BumpTypedBuffer(XChar2b, len);
4387 buffer = BfBuf(XChar2b);
4388
4389 for (src = dst = 0; src < (int) len; src++) {
4390 IChar ch = text[src];
4391
4392 if (ch == HIDDEN_CHAR)
4393 continue;
4394
4395 #if OPT_BOX_CHARS
4396 if ((screen->fnt_boxes == 1) && (ch >= 256)) {
4397 unsigned part = ucs2dec(screen, ch);
4398 if (part < 32)
4399 ch = (IChar) part;
4400 }
4401 #endif
4402
4403 if (!needWide
4404 && !IsIcon(screen)
4405 && ((recur.on_wide || CharWidth(screen, ch) > 1)
4406 && okFont(NormalWFont(screen)))) {
4407 needWide = True;
4408 }
4409 #if OPT_WIDER_ICHAR
4410 /*
4411 * bitmap-fonts are limited to 16-bits.
4412 */
4413 if (ch > NARROW_ICHAR) {
4414 ch = 0;
4415 }
4416 #endif
4417 buffer[dst].byte2 = LO_BYTE(ch);
4418 buffer[dst].byte1 = HI_BYTE(ch);
4419 #if OPT_MINI_LUIT
4420 #define UCS2SBUF(value) buffer[dst].byte2 = LO_BYTE(value);\
4421 buffer[dst].byte1 = HI_BYTE(value)
4422
4423 #define Map2Sbuf(from,to) (text[src] == from) { UCS2SBUF(to); }
4424
4425 if (screen->latin9_mode && !screen->utf8_mode && text[src] < 256) {
4426
4427 /* see http://www.cs.tut.fi/~jkorpela/latin9.html */
4428 /* *INDENT-OFF* */
4429 if Map2Sbuf(0xa4, 0x20ac)
4430 else if Map2Sbuf(0xa6, 0x0160)
4431 else if Map2Sbuf(0xa8, 0x0161)
4432 else if Map2Sbuf(0xb4, 0x017d)
4433 else if Map2Sbuf(0xb8, 0x017e)
4434 else if Map2Sbuf(0xbc, 0x0152)
4435 else if Map2Sbuf(0xbd, 0x0153)
4436 else if Map2Sbuf(0xbe, 0x0178)
4437 /* *INDENT-ON* */
4438
4439 }
4440 if (screen->unicode_font
4441 && (text[src] == ANSI_DEL ||
4442 text[src] < ANSI_SPA)) {
4443 unsigned ni = dec2ucs(screen,
4444 (unsigned) ((text[src] == ANSI_DEL)
4445 ? 0
4446 : text[src]));
4447 UCS2SBUF(ni);
4448 }
4449 #endif /* OPT_MINI_LUIT */
4450 ++dst;
4451 }
4452
4453 /*
4454 * Check for special case where the bold font lacks glyphs found in the
4455 * normal font, and drop down to normal fonts with overstriking to help
4456 * show the actual characters.
4457 */
4458 useBoldFont = ((recur.attr_flags & BOLDATTR(screen)) != 0);
4459 if (useBoldFont) {
4460 XTermFonts *norm = 0;
4461 XTermFonts *bold = 0;
4462 Bool noBold, noNorm;
4463
4464 (void) norm;
4465 if (needWide && okFont(BoldWFont(screen))) {
4466 norm = WhichVFontData(screen, fWide);
4467 bold = WhichVFontData(screen, fWBold);
4468 } else if (okFont(BoldFont(screen))) {
4469 norm = WhichVFontData(screen, fNorm);
4470 bold = WhichVFontData(screen, fBold);
4471 } else {
4472 useBoldFont = False;
4473 }
4474
4475 if (useBoldFont && FontIsIncomplete(bold)) {
4476 for (src = 0; src < (int) len; src++) {
4477 IChar ch = text[src];
4478
4479 if (ch == HIDDEN_CHAR)
4480 continue;
4481
4482 noBold = IsXtermMissingChar(screen, ch, bold);
4483 if (noBold) {
4484 noNorm = IsXtermMissingChar(screen, ch, norm);
4485 if (!noNorm) {
4486 useBoldFont = False;
4487 break;
4488 }
4489 }
4490 }
4491 }
4492 }
4493
4494 /* FIXME This is probably wrong. But it works. */
4495 underline_len = len;
4496
4497 /* Set the drawing font */
4498 if (!(recur.draw_flags & (DOUBLEHFONT | DOUBLEWFONT))) {
4499 VTwin *currentWin = WhichVWin(screen);
4500 VTFontEnum fntId;
4501 CgsEnum cgsId;
4502 Pixel fg = getCgsFore(recur.xw, currentWin, gc);
4503 Pixel bg = getCgsBack(recur.xw, currentWin, gc);
4504
4505 if (needWide
4506 && useBoldFont
4507 && okFont(BoldWFont(screen))) {
4508 fntId = fWBold;
4509 cgsId = gcWBold;
4510 } else if (needWide) {
4511 fntId = fWide;
4512 cgsId = gcWide;
4513 } else if (useBoldFont) {
4514 fntId = fBold;
4515 cgsId = gcBold;
4516 } else {
4517 fntId = fNorm;
4518 cgsId = gcNorm;
4519 }
4520
4521 setCgsFore(recur.xw, currentWin, cgsId, fg);
4522 setCgsBack(recur.xw, currentWin, cgsId, bg);
4523 gc = getCgsGC(recur.xw, currentWin, cgsId);
4524
4525 #if OPT_WIDE_ATTRS
4526 #if OPT_DEC_CHRSET
4527 if (!(CSET_DOUBLE(recur.this_chrset) || (recur.draw_flags & DOUBLEWFONT)))
4528 #endif
4529 need_clipping = fixupItalics(&recur,
4530 gc,
4531 getCgsFont(recur.xw,
4532 currentWin, gc),
4533 y, x, font_width, len);
4534 #endif
4535 if (fntId != fNorm) {
4536 XFontStruct *thisFp = WhichVFont(screen, fntId);
4537 ascent_adjust = (thisFp->ascent
4538 - NormalFont(screen)->ascent);
4539 if (thisFp->max_bounds.width ==
4540 NormalFont(screen)->max_bounds.width * 2) {
4541 underline_len = real_length = (Cardinal) (dst * 2);
4542 } else if (cgsId == gcWide || cgsId == gcWBold) {
4543 underline_len = real_length = (Cardinal) (dst * 2);
4544 xtermFillCells(&recur,
4545 gc,
4546 x,
4547 y - thisFp->ascent,
4548 real_length);
4549 }
4550 }
4551 }
4552
4553 if (recur.draw_flags & NOBACKGROUND) {
4554 XDrawString16(screen->display,
4555 VDrawable(screen), gc,
4556 x, y + y_shift + ascent_adjust,
4557 buffer, dst);
4558 } else if (dst <= MaxImageString) {
4559 XDrawImageString16(screen->display,
4560 VDrawable(screen), gc,
4561 x, y + y_shift + ascent_adjust,
4562 buffer, dst);
4563 } else {
4564 int b_pos;
4565 int b_max = MaxImageString;
4566 for (b_pos = 0; b_pos < dst; b_pos += b_max) {
4567 if (b_pos + b_max > dst)
4568 b_max = (dst - b_pos);
4569 XDrawImageString16(screen->display,
4570 VDrawable(screen), gc,
4571 x + (b_pos * FontWidth(screen)),
4572 y + y_shift + ascent_adjust,
4573 buffer + b_pos,
4574 b_max);
4575 }
4576 }
4577 #if OPT_WIDE_ATTRS
4578 if (need_clipping) {
4579 endClipping(screen, gc);
4580 }
4581 #endif
4582
4583 if ((recur.attr_flags & BOLDATTR(screen)) && (screen->enbolden || !useBoldFont)) {
4584 if (!(recur.draw_flags & (DOUBLEWFONT | DOUBLEHFONT))) {
4585 beginClipping(screen, gc, (Cardinal) font_width, len);
4586 }
4587 XDrawString16(screen->display, VDrawable(screen), gc,
4588 x + 1,
4589 y + y_shift + ascent_adjust,
4590 buffer, dst);
4591 if (!(recur.draw_flags & (DOUBLEWFONT | DOUBLEHFONT))) {
4592 endClipping(screen, gc);
4593 }
4594 }
4595
4596 } else
4597 #endif /* OPT_WIDE_CHARS */
4598 {
4599 int length = (int) len; /* X should have used unsigned */
4600 #if OPT_WIDE_CHARS
4601 char *buffer;
4602 int dst;
4603
4604 BumpTypedBuffer(char, len);
4605 buffer = BfBuf(char);
4606
4607 for (dst = 0; dst < length; ++dst)
4608 buffer[dst] = (char) LO_BYTE(text[dst]);
4609 #else
4610 char *buffer = (char *) text;
4611 #endif
4612
4613 #if OPT_WIDE_ATTRS
4614 #if OPT_DEC_CHRSET
4615 if (!(CSET_DOUBLE(recur.this_chrset) || (recur.draw_flags & DOUBLEWFONT)))
4616 #endif
4617 need_clipping = fixupItalics(&recur, gc, curFont,
4618 y, x, font_width, len);
4619 #endif
4620
4621 if (recur.draw_flags & NOBACKGROUND) {
4622 XDrawString(screen->display, VDrawable(screen), gc,
4623 x, y + y_shift, buffer, length);
4624 } else if (length <= MaxImageString) {
4625 XDrawImageString(screen->display, VDrawable(screen), gc,
4626 x, y + y_shift, buffer, length);
4627 } else {
4628 int b_pos;
4629 int b_max = MaxImageString;
4630 for (b_pos = 0; b_pos < length; b_pos += b_max) {
4631 if (b_pos + b_max > length)
4632 b_max = (length - b_pos);
4633 XDrawImageString(screen->display,
4634 VDrawable(screen), gc,
4635 x + (b_pos * FontWidth(screen)),
4636 y + y_shift,
4637 buffer + b_pos,
4638 b_max);
4639 }
4640 }
4641
4642 #if OPT_WIDE_ATTRS
4643 if (need_clipping) {
4644 endClipping(screen, gc);
4645 }
4646 #endif
4647 underline_len = (Cardinal) length;
4648 if ((recur.attr_flags & BOLDATTR(screen)) && screen->enbolden) {
4649 if (!(recur.draw_flags & (DOUBLEWFONT | DOUBLEHFONT))) {
4650 beginClipping(screen, gc, font_width, length);
4651 }
4652 XDrawString(screen->display, VDrawable(screen), gc,
4653 x + 1, y + y_shift, buffer, length);
4654 if (!(recur.draw_flags & (DOUBLEWFONT | DOUBLEHFONT))) {
4655 endClipping(screen, gc);
4656 }
4657 }
4658 }
4659
4660 drawUnderline(recur.xw,
4661 gc,
4662 recur.attr_flags,
4663 underline_len,
4664 font_width,
4665 x,
4666 y + y_shift,
4667 did_ul);
4668
4669 x += ((int) real_length) * FontWidth(screen);
4670 return x;
4671 }
4672
4673 #if OPT_WIDE_CHARS
4674 /*
4675 * Allocate buffer - workaround for wide-character interfaces.
4676 */
4677 void
4678 allocXtermChars(ScrnPtr *buffer, Cardinal length)
4679 {
4680 if (*buffer == 0) {
4681 *buffer = (ScrnPtr) XtMalloc(length);
4682 } else {
4683 *buffer = (ScrnPtr) XtRealloc((char *) *buffer, length);
4684 }
4685 }
4686 #endif
4687
4688 /* set up size hints for window manager; min 1 char by 1 char */
4689 void
4690 xtermSizeHints(XtermWidget xw, int scrollbarWidth)
4691 {
4692 TScreen *screen = TScreenOf(xw);
4693
4694 TRACE(("xtermSizeHints\n"));
4695 TRACE((" border %d\n", xw->core.border_width));
4696 TRACE((" scrollbar %d\n", scrollbarWidth));
4697
4698 xw->hints.base_width = 2 * screen->border + scrollbarWidth;
4699 xw->hints.base_height = 2 * screen->border;
4700
4701 #if OPT_TOOLBAR
4702 TRACE((" toolbar %d\n", ToolbarHeight(xw)));
4703
4704 xw->hints.base_height += ToolbarHeight(xw);
4705 xw->hints.base_height += BorderWidth(xw) * 2;
4706 xw->hints.base_width += BorderWidth(xw) * 2;
4707 #endif
4708
4709 if (xw->misc.resizeByPixel) {
4710 xw->hints.width_inc = 1;
4711 xw->hints.height_inc = 1;
4712 } else {
4713 xw->hints.width_inc = FontWidth(screen);
4714 xw->hints.height_inc = FontHeight(screen);
4715 }
4716 xw->hints.min_width = xw->hints.base_width + xw->hints.width_inc;
4717 xw->hints.min_height = xw->hints.base_height + xw->hints.height_inc;
4718
4719 xw->hints.width = MaxCols(screen) * FontWidth(screen) + xw->hints.min_width;
4720 xw->hints.height = MaxRows(screen) * FontHeight(screen) + xw->hints.min_height;
4721
4722 xw->hints.flags |= (PSize | PBaseSize | PMinSize | PResizeInc);
4723
4724 TRACE_HINTS(&(xw->hints));
4725 }
4726
4727 void
4728 getXtermSizeHints(XtermWidget xw)
4729 {
4730 TScreen *screen = TScreenOf(xw);
4731 long supp;
4732
4733 if (!XGetWMNormalHints(screen->display, VShellWindow(xw),
4734 &xw->hints, &supp))
4735 memset(&xw->hints, 0, sizeof(xw->hints));
4736 TRACE_HINTS(&(xw->hints));
4737 }
4738
4739 CgsEnum
4740 whichXtermCgs(XtermWidget xw, unsigned attr_flags, Bool hilite)
4741 {
4742 TScreen *screen = TScreenOf(xw);
4743 CgsEnum cgsId = gcMAX;
4744
4745 if (ReverseOrHilite(screen, attr_flags, hilite)) {
4746 if (attr_flags & BOLDATTR(screen)) {
4747 cgsId = gcBoldReverse;
4748 } else {
4749 cgsId = gcNormReverse;
4750 }
4751 } else {
4752 if (attr_flags & BOLDATTR(screen)) {
4753 cgsId = gcBold;
4754 } else {
4755 cgsId = gcNorm;
4756 }
4757 }
4758 return cgsId;
4759 }
4760
4761 /*
4762 * Returns a GC, selected according to the font (reverse/bold/normal) that is
4763 * required for the current position (implied). The GC is updated with the
4764 * current screen foreground and background colors.
4765 */
4766 GC
4767 updatedXtermGC(XtermWidget xw, unsigned attr_flags, CellColor fg_bg,
4768 Bool hilite)
4769 {
4770 TScreen *screen = TScreenOf(xw);
4771 VTwin *win = WhichVWin(screen);
4772 CgsEnum cgsId = whichXtermCgs(xw, attr_flags, hilite);
4773 Pixel my_fg = extract_fg(xw, fg_bg, attr_flags);
4774 Pixel my_bg = extract_bg(xw, fg_bg, attr_flags);
4775 Pixel fg_pix = getXtermFG(xw, attr_flags, (int) my_fg);
4776 Pixel bg_pix = getXtermBG(xw, attr_flags, (int) my_bg);
4777 Pixel xx_pix;
4778 #if OPT_HIGHLIGHT_COLOR
4779 Boolean reverse2 = ((attr_flags & INVERSE) && hilite);
4780 Pixel selbg_pix = T_COLOR(screen, HIGHLIGHT_BG);
4781 Pixel selfg_pix = T_COLOR(screen, HIGHLIGHT_FG);
4782 Boolean always = screen->hilite_color;
4783 Boolean use_selbg = (Boolean) (always &&
4784 isNotForeground(xw, fg_pix, bg_pix, selbg_pix));
4785 Boolean use_selfg = (Boolean) (always &&
4786 isNotBackground(xw, fg_pix, bg_pix, selfg_pix));
4787 #endif
4788
4789 (void) fg_bg;
4790 (void) my_bg;
4791 (void) my_fg;
4792
4793 /*
4794 * Discard video attributes overridden by colorXXXMode's.
4795 */
4796 checkVeryBoldColors(attr_flags, my_fg);
4797
4798 if (ReverseOrHilite(screen, attr_flags, hilite)) {
4799 #if OPT_HIGHLIGHT_COLOR
4800 if (!screen->hilite_color) {
4801 if (selbg_pix != T_COLOR(screen, TEXT_FG)
4802 && selbg_pix != fg_pix
4803 && selbg_pix != bg_pix
4804 && selbg_pix != xw->dft_foreground) {
4805 bg_pix = fg_pix;
4806 fg_pix = selbg_pix;
4807 }
4808 }
4809 #endif
4810 EXCHANGE(fg_pix, bg_pix, xx_pix);
4811 #if OPT_HIGHLIGHT_COLOR
4812 if (screen->hilite_color) {
4813 if (screen->hilite_reverse) {
4814 if (use_selbg) {
4815 if (use_selfg) {
4816 bg_pix = fg_pix;
4817 } else {
4818 fg_pix = bg_pix;
4819 bg_pix = selbg_pix;
4820 }
4821 }
4822 if (use_selfg)
4823 fg_pix = selfg_pix;
4824 }
4825 }
4826 #endif
4827 } else if ((attr_flags & INVERSE) && hilite) {
4828 #if OPT_HIGHLIGHT_COLOR
4829 if (!screen->hilite_color) {
4830 if (selbg_pix != T_COLOR(screen, TEXT_FG)
4831 && selbg_pix != fg_pix
4832 && selbg_pix != bg_pix
4833 && selbg_pix != xw->dft_foreground) {
4834 bg_pix = fg_pix;
4835 fg_pix = selbg_pix;
4836 }
4837 }
4838 #endif
4839 /* double-reverse... EXCHANGE(fg_pix, bg_pix, xx_pix); */
4840 #if OPT_HIGHLIGHT_COLOR
4841 if (screen->hilite_color) {
4842 if (screen->hilite_reverse) {
4843 if (use_selbg) {
4844 if (use_selfg ^ reverse2) {
4845 bg_pix = fg_pix;
4846 } else {
4847 fg_pix = bg_pix;
4848 }
4849 if (reverse2) {
4850 fg_pix = selbg_pix;
4851 } else {
4852 bg_pix = selbg_pix;
4853 }
4854 }
4855 if (use_selfg) {
4856 if (reverse2) {
4857 bg_pix = selfg_pix;
4858 } else {
4859 fg_pix = selfg_pix;
4860 }
4861 }
4862 }
4863 }
4864 #endif
4865 }
4866 #if OPT_HIGHLIGHT_COLOR
4867 if (!screen->hilite_color || !screen->hilite_reverse) {
4868 if (hilite && !screen->hilite_reverse) {
4869 if (use_selbg) {
4870 if (reverse2)
4871 fg_pix = selbg_pix;
4872 else
4873 bg_pix = selbg_pix;
4874 }
4875 if (use_selfg) {
4876 if (reverse2)
4877 bg_pix = selfg_pix;
4878 else
4879 fg_pix = selfg_pix;
4880 }
4881 }
4882 }
4883 #endif
4884
4885 #if OPT_BLINK_TEXT
4886 if ((screen->blink_state == ON) &&
4887 (!screen->blink_as_bold) &&
4888 (attr_flags & BLINK)) {
4889 fg_pix = bg_pix;
4890 }
4891 #endif
4892
4893 setCgsFore(xw, win, cgsId, fg_pix);
4894 setCgsBack(xw, win, cgsId, bg_pix);
4895 return getCgsGC(xw, win, cgsId);
4896 }
4897
4898 /*
4899 * Resets the foreground/background of the GC returned by 'updatedXtermGC()'
4900 * to the values that would be set in SGR_Foreground and SGR_Background. This
4901 * duplicates some logic, but only modifies 1/4 as many GC's.
4902 */
4903 void
4904 resetXtermGC(XtermWidget xw, unsigned attr_flags, Bool hilite)
4905 {
4906 TScreen *screen = TScreenOf(xw);
4907 VTwin *win = WhichVWin(screen);
4908 CgsEnum cgsId = whichXtermCgs(xw, attr_flags, hilite);
4909 Pixel fg_pix = getXtermFG(xw, attr_flags, xw->cur_foreground);
4910 Pixel bg_pix = getXtermBG(xw, attr_flags, xw->cur_background);
4911
4912 checkVeryBoldColors(attr_flags, xw->cur_foreground);
4913
4914 if (ReverseOrHilite(screen, attr_flags, hilite)) {
4915 setCgsFore(xw, win, cgsId, bg_pix);
4916 setCgsBack(xw, win, cgsId, fg_pix);
4917 } else {
4918 setCgsFore(xw, win, cgsId, fg_pix);
4919 setCgsBack(xw, win, cgsId, bg_pix);
4920 }
4921 }
4922
4923 #if OPT_ISO_COLORS
4924 /*
4925 * Extract the foreground-color index from a color pair.
4926 * If we've got BOLD or UNDERLINE color-mode active, those will be used.
4927 */
4928 Pixel
4929 extract_fg(XtermWidget xw, CellColor color, unsigned attr_flags)
4930 {
4931 unsigned fg = ExtractForeground(color);
4932
4933 if (TScreenOf(xw)->colorAttrMode
4934 || (fg == ExtractBackground(color))) {
4935 fg = MapToColorMode(fg, TScreenOf(xw), attr_flags);
4936 }
4937 return fg;
4938 }
4939
4940 /*
4941 * Extract the background-color index from a color pair.
4942 * If we've got INVERSE color-mode active, that will be used.
4943 */
4944 Pixel
4945 extract_bg(XtermWidget xw, CellColor color, unsigned attr_flags)
4946 {
4947 unsigned bg = ExtractBackground(color);
4948
4949 if (TScreenOf(xw)->colorAttrMode
4950 || (bg == ExtractForeground(color))) {
4951 if (TScreenOf(xw)->colorRVMode && (attr_flags & INVERSE))
4952 bg = COLOR_RV;
4953 }
4954 return bg;
4955 }
4956
4957 /*
4958 * Combine the current foreground and background into a single 8-bit number.
4959 * Note that we're storing the SGR foreground, since cur_foreground may be set
4960 * to COLOR_UL, COLOR_BD or COLOR_BL, which would make the code larger than 8
4961 * bits.
4962 *
4963 * This assumes that fg/bg are equal when we override with one of the special
4964 * attribute colors.
4965 */
4966 CellColor
4967 makeColorPair(XtermWidget xw)
4968 {
4969 CellColor result;
4970
4971 #if OPT_DIRECT_COLOR
4972 result.fg = xw->cur_foreground;
4973 result.bg = xw->cur_background;
4974 #else
4975 int fg = xw->cur_foreground;
4976 int bg = xw->cur_background;
4977 unsigned my_bg = okIndexedColor(bg) ? (unsigned) bg : 0;
4978 unsigned my_fg = okIndexedColor(fg) ? (unsigned) fg : my_bg;
4979
4980 result = (CellColor) (my_fg | (my_bg << COLOR_BITS));
4981 #endif
4982
4983 return result;
4984 }
4985
4986 /*
4987 * Using the "current" SGR background, clear a rectangle.
4988 */
4989 void
4990 ClearCurBackground(XtermWidget xw,
4991 int top,
4992 int left,
4993 unsigned height,
4994 unsigned width,
4995 unsigned fw)
4996 {
4997 TScreen *screen = TScreenOf(xw);
4998 int actual_rows = PlusStatusLine(screen, screen->max_row + 1);
4999 Boolean visible = (((int) width > 0)
5000 && ((left + (int) width) <= screen->max_col + 1)
5001 && (((int) height + top) <= actual_rows));
5002
5003 TRACE(("ClearCurBackground %d,%d %dx%d%s with %d %s\n",
5004 top, left, height, width,
5005 IsStatusShown(screen) ? "*" : "",
5006 xw->cur_background,
5007 visible ? "(ok)" : "(err)"));
5008
5009 if (VWindow(screen) && visible) {
5010 set_background(xw, xw->cur_background);
5011
5012 xtermClear2(xw,
5013 CursorX2(screen, left, fw),
5014 CursorY2(screen, top),
5015 (width * fw),
5016 (height * (unsigned) FontHeight(screen)));
5017
5018 set_background(xw, -1);
5019 }
5020 }
5021 #endif /* OPT_ISO_COLORS */
5022
5023 Pixel
5024 getXtermBackground(XtermWidget xw, unsigned attr_flags, int color)
5025 {
5026 Pixel result = T_COLOR(TScreenOf(xw), TEXT_BG);
5027
5028 #if OPT_ISO_COLORS
5029 if (color >= 0) {
5030 if_OPT_DIRECT_COLOR2_else(TScreenOf(xw), (attr_flags & ATR_DIRECT_BG), {
5031 result = (Pixel) color;
5032 }) if ((attr_flags & BG_COLOR) && (color < MAXCOLORS)) {
5033 result = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[color]);
5034 }
5035 }
5036 #else
5037 (void) attr_flags;
5038 (void) color;
5039 #endif
5040 return result;
5041 }
5042
5043 #if OPT_ISO_COLORS && OPT_WIDE_ATTRS
5044 #if OPT_SGR2_HASH
5045 typedef struct _DimColorHT {
5046 Pixel org;
5047 Pixel dim;
5048 } DimColorHT;
5049
5050 static unsigned
5051 jhash1(unsigned char *key, size_t len)
5052 {
5053 unsigned hash;
5054 size_t i;
5055
5056 for (hash = 0, i = 0; i < len; ++i) {
5057 hash += key[i];
5058 hash += (hash << 10);
5059 hash ^= (hash >> 6);
5060 }
5061 hash += (hash << 3);
5062 hash ^= (hash >> 11);
5063 hash += (hash << 15);
5064 return hash;
5065 }
5066
5067 static unsigned
5068 computeFaint(XtermWidget xw, unsigned value, unsigned compare)
5069 {
5070 TScreen *screen = TScreenOf(xw);
5071 if (screen->faint_relative) {
5072 value = (unsigned) ((value + compare) / 2);
5073 } else {
5074 value = (unsigned) ((2 * value) / 3);
5075 }
5076 return value;
5077 }
5078 #endif /* OPT_SGR2_HASH */
5079 #endif /* OPT_ISO_COLORS && OPT_WIDE_ATTRS */
5080
5081 Pixel
5082 getXtermForeground(XtermWidget xw, unsigned attr_flags, int color)
5083 {
5084 Pixel result = T_COLOR(TScreenOf(xw), TEXT_FG);
5085
5086 #if OPT_ISO_COLORS
5087 if_OPT_DIRECT_COLOR2_else(TScreenOf(xw), (attr_flags & ATR_DIRECT_FG), {
5088 result = (Pixel) color;
5089 })
5090 if ((attr_flags & FG_COLOR) &&
5091 (color >= 0 && color < MAXCOLORS)) {
5092 result = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[color]);
5093 }
5094 #else
5095 (void) attr_flags;
5096 (void) color;
5097 #endif
5098
5099 #if OPT_ISO_COLORS && OPT_WIDE_ATTRS
5100 if ((attr_flags & ATR_FAINT)) {
5101 #if OPT_SGR2_HASH
5102 #define DIM_IT(n) work.n = (unsigned short) computeFaint(xw, work.n, bkg.n)
5103 #define SizeOfHT ((unsigned) sizeof(unsigned long) * CHAR_BIT)
5104 static DimColorHT ht[SizeOfHT];
5105 Pixel bg = T_COLOR(TScreenOf(xw), TEXT_BG);
5106 XColor work;
5107 Pixel p;
5108
5109 if ((color >= 0)
5110 || (result != (Pixel) color)) {
5111 static unsigned long have = 0;
5112 static Boolean have_bg = False;
5113 static XColor bkg;
5114
5115 /* cache bkg color in r/g/b */
5116 if (!have_bg || bg != bkg.pixel) {
5117 bkg.pixel = bg;
5118 have_bg = QueryOneColor(xw, &bkg);
5119 have = 0; /* invalidate color cache */
5120 }
5121 if (have_bg) {
5122 unsigned hv;
5123 hv = jhash1((unsigned char *) &result, sizeof(result));
5124 hv %= SizeOfHT;
5125
5126 if ((have & (1UL << hv))
5127 && ht[hv].org == result) {
5128 result = ht[hv].dim; /* return cached color */
5129 } else {
5130 work.pixel = result;
5131 if (QueryOneColor(xw, &work)) {
5132 DIM_IT(red);
5133 DIM_IT(green);
5134 DIM_IT(blue);
5135 p = result;
5136 if (allocateBestRGB(xw, &work)) {
5137 result = work.pixel;
5138 }
5139
5140 /* cache the result */
5141 have |= (1UL << hv);
5142 ht[hv].org = p;
5143 ht[hv].dim = result;
5144 }
5145 }
5146 }
5147 }
5148 #else /* !OPT_SGR2_HASH */
5149 #define DIM_IT(n) work.n = (unsigned short) ((2 * (unsigned)work.n) / 3)
5150 static Pixel last_in;
5151 static Pixel last_out;
5152 if ((result != last_in)
5153 && ((color >= 0)
5154 || (result != (Pixel) color))) {
5155 XColor work;
5156 last_in = result;
5157 work.pixel = result;
5158 if (QueryOneColor(xw, &work)) {
5159 DIM_IT(red);
5160 DIM_IT(green);
5161 DIM_IT(blue);
5162 if (allocateBestRGB(xw, &work)) {
5163 result = work.pixel;
5164 }
5165 }
5166 last_out = result;
5167 } else {
5168 result = last_out;
5169 }
5170 #endif /* OPT_SGR2_HASH */
5171 }
5172 #endif
5173 return result;
5174 }
5175
5176 /*
5177 * Returns a single base character for the given cell.
5178 */
5179 unsigned
5180 getXtermCell(TScreen *screen, int row, int col)
5181 {
5182 CLineData *ld = getLineData(screen, row);
5183
5184 return ((ld && (col < (int) ld->lineSize))
5185 ? ld->charData[col]
5186 : (unsigned) ' ');
5187 }
5188
5189 /*
5190 * Sets a single base character for the given cell.
5191 */
5192 void
5193 putXtermCell(TScreen *screen, int row, int col, int ch)
5194 {
5195 LineData *ld = getLineData(screen, row);
5196
5197 if (ld && (col < (int) ld->lineSize)) {
5198 ld->charData[col] = (CharData) ch;
5199 if_OPT_WIDE_CHARS(screen, {
5200 size_t off;
5201 for_each_combData(off, ld) {
5202 ld->combData[off][col] = 0;
5203 }
5204 });
5205 }
5206 }
5207
5208 #if OPT_WIDE_CHARS
5209 /*
5210 * Add a combining character for the given cell
5211 */
5212 void
5213 addXtermCombining(TScreen *screen, int row, int col, unsigned ch)
5214 {
5215 if (ch != 0) {
5216 LineData *ld = getLineData(screen, row);
5217 size_t off;
5218
5219 TRACE(("addXtermCombining %d,%d U+%04X (%d)\n",
5220 row, col, ch, CharWidth(screen, ch)));
5221
5222 for_each_combData(off, ld) {
5223 if (!ld->combData[off][col]) {
5224 ld->combData[off][col] = (CharData) ch;
5225 break;
5226 }
5227 }
5228 }
5229 }
5230
5231 unsigned
5232 getXtermCombining(TScreen *screen, int row, int col, int off)
5233 {
5234 CLineData *ld = getLineData(screen, row);
5235 return (ld->combSize ? ld->combData[off][col] : 0U);
5236 }
5237 #endif
5238
5239 void
5240 update_keyboard_type(void)
5241 {
5242 update_delete_del();
5243 update_tcap_fkeys();
5244 update_old_fkeys();
5245 update_hp_fkeys();
5246 update_sco_fkeys();
5247 update_sun_fkeys();
5248 update_sun_kbd();
5249 }
5250
5251 void
5252 set_keyboard_type(XtermWidget xw, xtermKeyboardType type, Bool set)
5253 {
5254 xtermKeyboardType save = xw->keyboard.type;
5255
5256 TRACE(("set_keyboard_type(%s, %s) currently %s\n",
5257 visibleKeyboardType(type),
5258 BtoS(set),
5259 visibleKeyboardType(xw->keyboard.type)));
5260 if (set) {
5261 xw->keyboard.type = type;
5262 } else {
5263 xw->keyboard.type = keyboardIsDefault;
5264 }
5265
5266 if (save != xw->keyboard.type) {
5267 update_keyboard_type();
5268 }
5269 }
5270
5271 void
5272 toggle_keyboard_type(XtermWidget xw, xtermKeyboardType type)
5273 {
5274 xtermKeyboardType save = xw->keyboard.type;
5275
5276 TRACE(("toggle_keyboard_type(%s) currently %s\n",
5277 visibleKeyboardType(type),
5278 visibleKeyboardType(xw->keyboard.type)));
5279 if (xw->keyboard.type == type) {
5280 xw->keyboard.type = keyboardIsDefault;
5281 } else {
5282 xw->keyboard.type = type;
5283 }
5284
5285 if (save != xw->keyboard.type) {
5286 update_keyboard_type();
5287 }
5288 }
5289
5290 const char *
5291 visibleKeyboardType(xtermKeyboardType type)
5292 {
5293 const char *result = "?";
5294 switch (type) {
5295 CASETYPE(keyboardIsLegacy); /* bogus vt220 codes for F1-F4, etc. */
5296 CASETYPE(keyboardIsDefault);
5297 CASETYPE(keyboardIsHP);
5298 CASETYPE(keyboardIsSCO);
5299 CASETYPE(keyboardIsSun);
5300 CASETYPE(keyboardIsTermcap);
5301 CASETYPE(keyboardIsVT220);
5302 }
5303 return result;
5304 }
5305
5306 static void
5307 init_keyboard_type(XtermWidget xw, xtermKeyboardType type, Bool set)
5308 {
5309 TRACE(("init_keyboard_type(%s, %s) currently %s\n",
5310 visibleKeyboardType(type),
5311 BtoS(set),
5312 visibleKeyboardType(xw->keyboard.type)));
5313 if (set) {
5314 /*
5315 * Check for conflicts, e.g., if someone asked for both Sun and HP
5316 * function keys.
5317 */
5318 if (guard_keyboard_type) {
5319 xtermWarning("Conflicting keyboard type option (%s/%s)\n",
5320 visibleKeyboardType(xw->keyboard.type),
5321 visibleKeyboardType(type));
5322 }
5323 xw->keyboard.type = type;
5324 guard_keyboard_type = True;
5325 update_keyboard_type();
5326 }
5327 }
5328
5329 /*
5330 * If the keyboardType resource is set, use that, overriding the individual
5331 * boolean resources for different keyboard types.
5332 */
5333 void
5334 decode_keyboard_type(XtermWidget xw, XTERM_RESOURCE * rp)
5335 {
5336 #define DATA(n, t, f) { n, t, XtOffsetOf(XTERM_RESOURCE, f) }
5337 #define FLAG(n) *(Boolean *)(((char *)rp) + table[n].offset)
5338 static struct {
5339 const char *name;
5340 xtermKeyboardType type;
5341 unsigned offset;
5342 } table[] = {
5343 DATA(NAME_OLD_KT, keyboardIsLegacy, oldKeyboard),
5344 #if OPT_HP_FUNC_KEYS
5345 DATA(NAME_HP_KT, keyboardIsHP, hpFunctionKeys),
5346 #endif
5347 #if OPT_SCO_FUNC_KEYS
5348 DATA(NAME_SCO_KT, keyboardIsSCO, scoFunctionKeys),
5349 #endif
5350 #if OPT_SUN_FUNC_KEYS
5351 DATA(NAME_SUN_KT, keyboardIsSun, sunFunctionKeys),
5352 #endif
5353 #if OPT_SUNPC_KBD
5354 DATA(NAME_VT220_KT, keyboardIsVT220, sunKeyboard),
5355 #endif
5356 #if OPT_TCAP_FKEYS
5357 DATA(NAME_TCAP_KT, keyboardIsTermcap, termcapKeys),
5358 #endif
5359 };
5360 Cardinal n;
5361 TScreen *screen = TScreenOf(xw);
5362
5363 TRACE(("decode_keyboard_type(%s)\n", rp->keyboardType));
5364 if (!x_strcasecmp(rp->keyboardType, "unknown")) {
5365 /*
5366 * Let the individual resources comprise the keyboard-type.
5367 */
5368 for (n = 0; n < XtNumber(table); ++n)
5369 init_keyboard_type(xw, table[n].type, FLAG(n));
5370 } else if (!x_strcasecmp(rp->keyboardType, "default")) {
5371 /*
5372 * Set the keyboard-type to the Sun/PC type, allowing modified
5373 * function keys, etc.
5374 */
5375 for (n = 0; n < XtNumber(table); ++n)
5376 init_keyboard_type(xw, table[n].type, False);
5377 } else {
5378 Bool found = False;
5379
5380 /*
5381 * Special case: oldXtermFKeys should have been like the others.
5382 */
5383 if (!x_strcasecmp(rp->keyboardType, NAME_OLD_KT)) {
5384 TRACE(("special case, setting oldXtermFKeys\n"));
5385 screen->old_fkeys = True;
5386 screen->old_fkeys0 = True;
5387 }
5388
5389 /*
5390 * Choose an individual keyboard type.
5391 */
5392 for (n = 0; n < XtNumber(table); ++n) {
5393 if (!x_strcasecmp(rp->keyboardType, table[n].name + 1))