1 /* $XTermId: screen.c,v 1.604 2021/11/05 08:00:28 tom Exp $ */
2
3 /*
4 * Copyright 1999-2020,2021 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 /* screen.c */
56
57 #include <stdio.h>
58 #include <xterm.h>
59 #include <error.h>
60 #include <data.h>
61 #include <xterm_io.h>
62
63 #include <X11/Xatom.h>
64
65 #if OPT_WIDE_ATTRS || OPT_WIDE_CHARS
66 #include <fontutils.h>
67 #endif
68
69 #include <menu.h>
70
71 #include <assert.h>
72 #include <signal.h>
73
74 #include <graphics.h>
75
76 #define inSaveBuf(screen, buf, inx) \
77 ((buf) == (screen)->saveBuf_index && \
78 ((inx) < (screen)->savelines || (screen)->savelines == 0))
79
80 #define getMinRow(screen) ((xw->flags & ORIGIN) ? (screen)->top_marg : 0)
81 #define getMaxRow(screen) ((xw->flags & ORIGIN) ? (screen)->bot_marg : (screen)->max_row)
82 #define getMinCol(screen) ((xw->flags & ORIGIN) ? (screen)->lft_marg : 0)
83 #define getMaxCol(screen) ((xw->flags & ORIGIN) ? (screen)->rgt_marg : (screen)->max_col)
84
85 #define MoveLineData(base, dst, src, len) \
86 memmove(scrnHeadAddr(screen, base, (unsigned) (dst)), \
87 scrnHeadAddr(screen, base, (unsigned) (src)), \
88 (size_t) scrnHeadSize(screen, (unsigned) (len)))
89
90 #define SaveLineData(base, src, len) \
91 (void) ScrnPointers(screen, len); \
92 memcpy (screen->save_ptr, \
93 scrnHeadAddr(screen, base, src), \
94 (size_t) scrnHeadSize(screen, (unsigned) (len)))
95
96 #define RestoreLineData(base, dst, len) \
97 memcpy (scrnHeadAddr(screen, base, dst), \
98 screen->save_ptr, \
99 (size_t) scrnHeadSize(screen, (unsigned) (len)))
100
101 #define VisBuf(screen) screen->editBuf_index[screen->whichBuf]
102
103 /*
104 * ScrnPtr's can point to different types of data.
105 */
106 #define SizeofScrnPtr(name) \
107 (unsigned) sizeof(*((LineData *)0)->name)
108
109 /*
110 * The pointers in LineData point into a block of text allocated as a single
111 * chunk for the given number of rows. Ensure that these pointers are aligned
112 * at least to int-boundaries.
113 */
114 #define AlignMask() (sizeof(int) - 1)
115 #define IsAligned(value) (((unsigned long) (value) & AlignMask()) == 0)
116
117 #define AlignValue(value) \
118 if (!IsAligned(value)) \
119 value = (value | (unsigned) AlignMask()) + 1
120
121 #define SetupScrnPtr(dst,src,type) \
122 dst = (type *) (void *) src; \
123 assert(IsAligned(dst)); \
124 src += skipNcol##type
125
126 #define ScrnBufAddr(ptrs, offset) (ScrnBuf) ((void *) ((char *) (ptrs) + (offset)))
127 #define LineDataAddr(ptrs, offset) (LineData *) ((void *) ((char *) (ptrs) + (offset)))
128
129 #if OPT_TRACE > 1
130 static void
traceScrnBuf(const char * tag,TScreen * screen,ScrnBuf sb,unsigned len)131 traceScrnBuf(const char *tag, TScreen *screen, ScrnBuf sb, unsigned len)
132 {
133 unsigned j;
134
135 TRACE(("traceScrnBuf %s\n", tag));
136 for (j = 0; j < len; ++j) {
137 LineData *src = (LineData *) scrnHeadAddr(screen, sb, j);
138 TRACE(("%p %s%3d:%s\n",
139 src, ((int) j >= screen->savelines) ? "*" : " ",
140 j, visibleIChars(src->charData, src->lineSize)));
141 }
142 TRACE(("...traceScrnBuf %s\n", tag));
143 }
144
145 #define TRACE_SCRNBUF(tag, screen, sb, len) traceScrnBuf(tag, screen, sb, len)
146 #else
147 #define TRACE_SCRNBUF(tag, screen, sb, len) /*nothing */
148 #endif
149
150 #if OPT_WIDE_CHARS
151 #define scrnHeadSize(screen, count) \
152 (unsigned) ((count) * \
153 (SizeOfLineData + \
154 ((screen)->wide_chars \
155 ? (unsigned) (screen)->lineExtra \
156 : 0)))
157 #else
158 #define scrnHeadSize(screen, count) \
159 (unsigned) ((count) * \
160 SizeOfLineData)
161 #endif
162
163 ScrnBuf
scrnHeadAddr(TScreen * screen,ScrnBuf base,unsigned offset)164 scrnHeadAddr(TScreen *screen, ScrnBuf base, unsigned offset)
165 {
166 unsigned size = scrnHeadSize(screen, offset);
167 ScrnBuf result = ScrnBufAddr(base, size);
168
169 (void) screen;
170 assert((int) offset >= 0);
171
172 return result;
173 }
174
175 /*
176 * Given a block of data, build index to it in the 'base' parameter.
177 */
178 void
setupLineData(TScreen * screen,ScrnBuf base,Char * data,unsigned nrow,unsigned ncol)179 setupLineData(TScreen *screen, ScrnBuf base, Char *data, unsigned nrow, unsigned ncol)
180 {
181 unsigned i;
182 unsigned offset = 0;
183 unsigned jump = scrnHeadSize(screen, 1);
184 LineData *ptr;
185 #if OPT_WIDE_CHARS
186 unsigned j;
187 #endif
188 /* these names are based on types */
189 unsigned skipNcolIAttr;
190 unsigned skipNcolCharData;
191 #if OPT_ISO_COLORS
192 unsigned skipNcolCellColor;
193 #endif
194
195 (void) screen;
196 AlignValue(ncol);
197
198 skipNcolIAttr = (ncol * SizeofScrnPtr(attribs));
199 skipNcolCharData = (ncol * SizeofScrnPtr(charData));
200 #if OPT_ISO_COLORS
201 skipNcolCellColor = (ncol * SizeofScrnPtr(color));
202 #endif
203
204 for (i = 0; i < nrow; i++, offset += jump) {
205 ptr = LineDataAddr(base, offset);
206
207 ptr->lineSize = (Dimension) ncol;
208 ptr->bufHead = 0;
209 #if OPT_DEC_CHRSET
210 SetLineDblCS(ptr, 0);
211 #endif
212 SetupScrnPtr(ptr->attribs, data, IAttr);
213 #if OPT_ISO_COLORS
214 SetupScrnPtr(ptr->color, data, CellColor);
215 #endif
216 SetupScrnPtr(ptr->charData, data, CharData);
217 #if OPT_WIDE_CHARS
218 if (screen->wide_chars) {
219 unsigned extra = (unsigned) screen->max_combining;
220
221 ptr->combSize = (Char) extra;
222 for (j = 0; j < extra; ++j) {
223 SetupScrnPtr(ptr->combData[j], data, CharData);
224 }
225 }
226 #endif
227 }
228 }
229
230 #define ExtractScrnData(name) \
231 memcpy(dstPtrs->name, \
232 ((LineData *) srcPtrs)->name,\
233 dstCols * sizeof(dstPtrs->name[0])); \
234 nextPtr += (srcCols * sizeof(dstPtrs->name[0]))
235
236 /*
237 * As part of reallocating the screen buffer when resizing, extract from
238 * the old copy of the screen buffer the data which will be used in the
239 * new copy of the screen buffer.
240 */
241 static void
extractScrnData(TScreen * screen,ScrnBuf dstPtrs,ScrnBuf srcPtrs,unsigned nrows,unsigned move_down)242 extractScrnData(TScreen *screen,
243 ScrnBuf dstPtrs,
244 ScrnBuf srcPtrs,
245 unsigned nrows,
246 unsigned move_down)
247 {
248 unsigned j;
249
250 TRACE(("extractScrnData(nrows %d)\n", nrows));
251
252 TRACE_SCRNBUF("extract from", screen, srcPtrs, nrows);
253 for (j = 0; j < nrows; j++) {
254 LineData *dst = (LineData *) scrnHeadAddr(screen,
255 dstPtrs, j + move_down);
256 LineData *src = (LineData *) scrnHeadAddr(screen,
257 srcPtrs, j);
258 copyLineData(dst, src);
259 }
260 }
261
262 static ScrnPtr *
allocScrnHead(TScreen * screen,unsigned nrow)263 allocScrnHead(TScreen *screen, unsigned nrow)
264 {
265 ScrnPtr *result;
266 unsigned size = scrnHeadSize(screen, 1);
267
268 (void) screen;
269 result = (ScrnPtr *) calloc((size_t) nrow, (size_t) size);
270 if (result == 0)
271 SysError(ERROR_SCALLOC);
272
273 TRACE(("allocScrnHead %d -> %d -> %p..%p\n", nrow, nrow * size,
274 (void *) result,
275 (char *) result + (nrow * size) - 1));
276 return result;
277 }
278
279 /*
280 * Return the size of a line's data.
281 */
282 static unsigned
sizeofScrnRow(TScreen * screen,unsigned ncol)283 sizeofScrnRow(TScreen *screen, unsigned ncol)
284 {
285 unsigned result;
286 unsigned sizeAttribs;
287 #if OPT_ISO_COLORS
288 unsigned sizeColors;
289 #endif
290
291 (void) screen;
292
293 result = (ncol * (unsigned) sizeof(CharData));
294 AlignValue(result);
295
296 #if OPT_WIDE_CHARS
297 if (screen->wide_chars) {
298 result *= (unsigned) (1 + screen->max_combining);
299 }
300 #endif
301
302 sizeAttribs = (ncol * SizeofScrnPtr(attribs));
303 AlignValue(sizeAttribs);
304 result += sizeAttribs;
305
306 #if OPT_ISO_COLORS
307 sizeColors = (ncol * SizeofScrnPtr(color));
308 AlignValue(sizeColors);
309 result += sizeColors;
310 #endif
311
312 return result;
313 }
314
315 Char *
allocScrnData(TScreen * screen,unsigned nrow,unsigned ncol)316 allocScrnData(TScreen *screen, unsigned nrow, unsigned ncol)
317 {
318 Char *result = 0;
319 size_t length;
320
321 AlignValue(ncol);
322 length = ((nrow + 1) * sizeofScrnRow(screen, ncol));
323 if (length == 0
324 || (result = (Char *) calloc(length, sizeof(Char))) == 0)
325 SysError(ERROR_SCALLOC2);
326
327 TRACE(("allocScrnData %ux%u -> %lu -> %p..%p\n",
328 nrow, ncol, (unsigned long) length, result, result + length - 1));
329 return result;
330 }
331
332 /*
333 * Allocates memory for a 2-dimensional array of chars and returns a pointer
334 * thereto. Each line is formed from a set of char arrays, with an index
335 * (i.e., the ScrnBuf type). The first pointer in the index is reserved for
336 * per-line flags, and does not point to data.
337 *
338 * After the per-line flags, we have a series of pointers to char arrays: The
339 * first one is the actual character array, the second one is the attributes,
340 * the third is the foreground and background colors, and the fourth denotes
341 * the character set.
342 *
343 * We store it all as pointers, because of alignment considerations.
344 */
345 ScrnBuf
allocScrnBuf(XtermWidget xw,unsigned nrow,unsigned ncol,Char ** addr)346 allocScrnBuf(XtermWidget xw, unsigned nrow, unsigned ncol, Char **addr)
347 {
348 TScreen *screen = TScreenOf(xw);
349 ScrnBuf base = 0;
350
351 if (nrow != 0) {
352 base = allocScrnHead(screen, nrow);
353 *addr = allocScrnData(screen, nrow, ncol);
354
355 setupLineData(screen, base, *addr, nrow, ncol);
356 }
357
358 TRACE(("allocScrnBuf %dx%d ->%p\n", nrow, ncol, (void *) base));
359 return (base);
360 }
361
362 /*
363 * Copy line-data from the visible (edit) buffer to the save-lines buffer.
364 */
365 static void
saveEditBufLines(TScreen * screen,unsigned n)366 saveEditBufLines(TScreen *screen, unsigned n)
367 {
368 unsigned j;
369
370 TRACE(("...copying %d lines from editBuf to saveBuf\n", n));
371
372 for (j = 0; j < n; ++j) {
373
374 LineData *dst = addScrollback(screen);
375
376 LineData *src = getLineData(screen, (int) j);
377 copyLineData(dst, src);
378 }
379 }
380
381 /*
382 * Copy line-data from the save-lines buffer to the visible (edit) buffer.
383 */
384 static void
unsaveEditBufLines(TScreen * screen,ScrnBuf sb,unsigned n)385 unsaveEditBufLines(TScreen *screen, ScrnBuf sb, unsigned n)
386 {
387 unsigned j;
388
389 TRACE(("...copying %d lines from saveBuf to editBuf\n", n));
390 for (j = 0; j < n; ++j) {
391 int extra = (int) (n - j);
392 LineData *dst = (LineData *) scrnHeadAddr(screen, sb, j);
393
394 CLineData *src;
395
396 if (extra > screen->saved_fifo || extra > screen->savelines) {
397 TRACE(("...FIXME: must clear text!\n"));
398 continue;
399 }
400 src = getScrollback(screen, -extra);
401
402 copyLineData(dst, src);
403 }
404 }
405
406 /*
407 * This is called when the screen is resized.
408 * Returns the number of lines the text was moved down (neg for up).
409 * (Return value only necessary with SouthWestGravity.)
410 */
411 static int
Reallocate(XtermWidget xw,ScrnBuf * sbuf,Char ** sbufaddr,unsigned nrow,unsigned ncol,unsigned oldrow)412 Reallocate(XtermWidget xw,
413 ScrnBuf *sbuf,
414 Char **sbufaddr,
415 unsigned nrow,
416 unsigned ncol,
417 unsigned oldrow)
418 {
419 TScreen *screen = TScreenOf(xw);
420 ScrnBuf oldBufHead;
421 ScrnBuf newBufHead;
422 Char *newBufData;
423 unsigned minrows;
424 Char *oldBufData;
425 int move_down = 0, move_up = 0;
426
427 if (sbuf == NULL || *sbuf == NULL) {
428 return 0;
429 }
430
431 oldBufData = *sbufaddr;
432
433 TRACE(("Reallocate %dx%d -> %dx%d\n", oldrow, MaxCols(screen), nrow, ncol));
434
435 /*
436 * realloc sbuf, the pointers to all the lines.
437 * If the screen shrinks, remove lines off the top of the buffer
438 * if resizeGravity resource says to do so.
439 */
440 TRACE(("Check move_up, nrow %d vs oldrow %d (resizeGravity %s)\n",
441 nrow, oldrow,
442 BtoS(GravityIsSouthWest(xw))));
443 if (GravityIsSouthWest(xw)) {
444 if (nrow < oldrow) {
445 /* Remove lines off the top of the buffer if necessary. */
446 move_up = (int) (oldrow - nrow)
447 - (TScreenOf(xw)->max_row - TScreenOf(xw)->cur_row);
448 if (move_up < 0)
449 move_up = 0;
450 /* Overlapping move here! */
451 TRACE(("move_up %d\n", move_up));
452 if (move_up) {
453 ScrnBuf dst = *sbuf;
454 unsigned len = (unsigned) ((int) oldrow - move_up);
455
456 TRACE_SCRNBUF("before move_up", screen, dst, oldrow);
457 SaveLineData(dst, 0, (size_t) move_up);
458 MoveLineData(dst, 0, (size_t) move_up, len);
459 RestoreLineData(dst, len, (size_t) move_up);
460 TRACE_SCRNBUF("after move_up", screen, dst, oldrow);
461 }
462 }
463 }
464 oldBufHead = *sbuf;
465 *sbuf = allocScrnHead(screen, (unsigned) nrow);
466 newBufHead = *sbuf;
467
468 /*
469 * Create the new buffer space and copy old buffer contents there, line by
470 * line.
471 */
472 newBufData = allocScrnData(screen, nrow, ncol);
473 *sbufaddr = newBufData;
474
475 minrows = (oldrow < nrow) ? oldrow : nrow;
476 if (GravityIsSouthWest(xw)) {
477 if (nrow > oldrow) {
478 /* move data down to bottom of expanded screen */
479 move_down = Min((int) (nrow - oldrow), TScreenOf(xw)->savedlines);
480 }
481 }
482
483 setupLineData(screen, newBufHead, *sbufaddr, nrow, ncol);
484 extractScrnData(screen, newBufHead, oldBufHead, minrows, 0);
485
486 /* Now free the old data */
487 free(oldBufData);
488 free(oldBufHead);
489
490 TRACE(("...Reallocate %dx%d ->%p\n", nrow, ncol, (void *) newBufHead));
491 return move_down ? move_down : -move_up; /* convert to rows */
492 }
493
494 #if OPT_WIDE_CHARS
495 /*
496 * This function reallocates memory if changing the number of Buf offsets.
497 * The code is based on Reallocate().
498 */
499 static void
ReallocateBufOffsets(XtermWidget xw,ScrnBuf * sbuf,Char ** sbufaddr,unsigned nrow,unsigned ncol)500 ReallocateBufOffsets(XtermWidget xw,
501 ScrnBuf *sbuf,
502 Char **sbufaddr,
503 unsigned nrow,
504 unsigned ncol)
505 {
506 TScreen *screen = TScreenOf(xw);
507 unsigned i;
508 ScrnBuf newBufHead;
509 Char *oldBufData;
510 ScrnBuf oldBufHead;
511
512 unsigned old_jump = scrnHeadSize(screen, 1);
513 unsigned new_jump;
514 unsigned new_ptrs = 1 + (unsigned) (screen->max_combining);
515 unsigned dstCols = ncol;
516 unsigned srcCols = ncol;
517 LineData *dstPtrs;
518 LineData *srcPtrs;
519 Char *nextPtr;
520
521 assert(nrow != 0);
522 assert(ncol != 0);
523
524 oldBufData = *sbufaddr;
525 oldBufHead = *sbuf;
526
527 /*
528 * Allocate a new LineData array, retain the old one until we've copied
529 * the data that it points to, as well as non-pointer data, e.g., bufHead.
530 *
531 * Turn on wide-chars temporarily when constructing pointers, since that is
532 * used to decide whether to address the combData[] array, which affects
533 * the length of the LineData structure.
534 */
535 screen->wide_chars = True;
536
537 new_jump = scrnHeadSize(screen, 1);
538 newBufHead = allocScrnHead(screen, nrow);
539 *sbufaddr = allocScrnData(screen, nrow, ncol);
540 setupLineData(screen, newBufHead, *sbufaddr, nrow, ncol);
541
542 screen->wide_chars = False;
543
544 nextPtr = *sbufaddr;
545
546 srcPtrs = (LineData *) oldBufHead;
547 dstPtrs = (LineData *) newBufHead;
548 for (i = 0; i < nrow; i++) {
549 dstPtrs->bufHead = srcPtrs->bufHead;
550 ExtractScrnData(attribs);
551 #if OPT_ISO_COLORS
552 ExtractScrnData(color);
553 #endif
554 ExtractScrnData(charData);
555
556 nextPtr += ncol * new_ptrs;
557 srcPtrs = LineDataAddr(srcPtrs, old_jump);
558 dstPtrs = LineDataAddr(dstPtrs, new_jump);
559 }
560
561 /* Now free the old data */
562 free(oldBufData);
563 free(oldBufHead);
564
565 *sbuf = newBufHead;
566
567 TRACE(("ReallocateBufOffsets %dx%d ->%p\n", nrow, ncol, *sbufaddr));
568 }
569
570 /*
571 * Allocate a new FIFO index.
572 */
573 static void
ReallocateFifoIndex(XtermWidget xw)574 ReallocateFifoIndex(XtermWidget xw)
575 {
576 TScreen *screen = TScreenOf(xw);
577
578 if (screen->savelines > 0 && screen->saveBuf_index != 0) {
579 ScrnBuf newBufHead;
580 LineData *dstPtrs;
581 LineData *srcPtrs;
582 unsigned i;
583 unsigned old_jump = scrnHeadSize(screen, 1);
584 unsigned new_jump;
585
586 screen->wide_chars = True;
587 newBufHead = allocScrnHead(screen, (unsigned) screen->savelines);
588 new_jump = scrnHeadSize(screen, 1);
589
590 srcPtrs = (LineData *) screen->saveBuf_index;
591 dstPtrs = (LineData *) newBufHead;
592
593 for (i = 0; i < (unsigned) screen->savelines; ++i) {
594 memcpy(dstPtrs, srcPtrs, SizeOfLineData);
595 srcPtrs = LineDataAddr(srcPtrs, old_jump);
596 dstPtrs = LineDataAddr(dstPtrs, new_jump);
597 }
598
599 screen->wide_chars = False;
600 free(screen->saveBuf_index);
601 screen->saveBuf_index = newBufHead;
602 }
603 }
604
605 /*
606 * This function dynamically adds support for wide-characters.
607 */
608 void
ChangeToWide(XtermWidget xw)609 ChangeToWide(XtermWidget xw)
610 {
611 TScreen *screen = TScreenOf(xw);
612
613 if (screen->wide_chars)
614 return;
615
616 TRACE(("ChangeToWide\n"));
617 if (xtermLoadWideFonts(xw, True)) {
618 int whichBuf = screen->whichBuf;
619
620 /*
621 * If we're displaying the alternate screen, switch the pointers back
622 * temporarily so ReallocateBufOffsets() will operate on the proper
623 * data in the alternate buffer.
624 */
625 if (screen->whichBuf)
626 SwitchBufPtrs(screen, 0);
627
628 ReallocateFifoIndex(xw);
629
630 if (screen->editBuf_index[0]) {
631 ReallocateBufOffsets(xw,
632 &screen->editBuf_index[0],
633 &screen->editBuf_data[0],
634 (unsigned) MaxRows(screen),
635 (unsigned) MaxCols(screen));
636 }
637
638 if (screen->editBuf_index[1]) {
639 ReallocateBufOffsets(xw,
640 &screen->editBuf_index[1],
641 &screen->editBuf_data[1],
642 (unsigned) MaxRows(screen),
643 (unsigned) MaxCols(screen));
644 }
645
646 screen->wide_chars = True;
647 screen->visbuf = VisBuf(screen);
648
649 /*
650 * Switch the pointers back before we start painting on the screen.
651 */
652 if (whichBuf)
653 SwitchBufPtrs(screen, whichBuf);
654
655 update_font_utf8_mode();
656 SetVTFont(xw, screen->menu_font_number, True, NULL);
657 }
658 TRACE(("...ChangeToWide\n"));
659 }
660 #endif
661
662 /*
663 * Copy cells, no side-effects.
664 */
665 void
CopyCells(TScreen * screen,LineData * src,LineData * dst,int col,int len,Bool down)666 CopyCells(TScreen *screen, LineData *src, LineData *dst, int col, int len, Bool down)
667 {
668 (void) screen;
669 (void) down;
670
671 if (len > 0) {
672 int n;
673 int last = col + len;
674 #if OPT_WIDE_CHARS
675 int fix_l = -1;
676 int fix_r = -1;
677 #endif
678
679 /*
680 * If the copy overwrites a double-width character which has one half
681 * outside the margin, then we will replace both cells with blanks.
682 */
683 if_OPT_WIDE_CHARS(screen, {
684 if (col > 0) {
685 if (dst->charData[col] == HIDDEN_CHAR) {
686 if (down) {
687 Clear2Cell(dst, src, col - 1);
688 Clear2Cell(dst, src, col);
689 } else {
690 if (src->charData[col] != HIDDEN_CHAR) {
691 Clear2Cell(dst, src, col - 1);
692 Clear2Cell(dst, src, col);
693 } else {
694 fix_l = col - 1;
695 }
696 }
697 } else if (src->charData[col] == HIDDEN_CHAR) {
698 Clear2Cell(dst, src, col - 1);
699 Clear2Cell(dst, src, col);
700 ++col;
701 }
702 }
703 if (last < (int) src->lineSize) {
704 if (dst->charData[last] == HIDDEN_CHAR) {
705 if (down) {
706 Clear2Cell(dst, src, last - 1);
707 Clear2Cell(dst, src, last);
708 } else {
709 if (src->charData[last] != HIDDEN_CHAR) {
710 Clear2Cell(dst, src, last);
711 } else {
712 fix_r = last - 1;
713 }
714 }
715 } else if (src->charData[last] == HIDDEN_CHAR) {
716 last--;
717 Clear2Cell(dst, src, last);
718 }
719 }
720 });
721
722 for (n = col; n < last; ++n) {
723 dst->charData[n] = src->charData[n];
724 dst->attribs[n] = src->attribs[n];
725 }
726
727 if_OPT_ISO_COLORS(screen, {
728 for (n = col; n < last; ++n) {
729 dst->color[n] = src->color[n];
730 }
731 });
732
733 if_OPT_WIDE_CHARS(screen, {
734 size_t off;
735 for (n = col; n < last; ++n) {
736 for_each_combData(off, src) {
737 dst->combData[off][n] = src->combData[off][n];
738 }
739 }
740 });
741
742 if_OPT_WIDE_CHARS(screen, {
743 if (fix_l >= 0) {
744 Clear2Cell(dst, src, fix_l);
745 Clear2Cell(dst, src, fix_l + 1);
746 }
747 if (fix_r >= 0) {
748 Clear2Cell(dst, src, fix_r);
749 Clear2Cell(dst, src, fix_r + 1);
750 }
751 });
752 }
753 }
754
755 static void
FillIAttr(IAttr * target,unsigned source,size_t count)756 FillIAttr(IAttr * target, unsigned source, size_t count)
757 {
758 while (count-- != 0) {
759 *target++ = (IAttr) source;
760 }
761 }
762
763 /*
764 * Clear cells, no side-effects.
765 */
766 void
ClearCells(XtermWidget xw,int flags,unsigned len,int row,int col)767 ClearCells(XtermWidget xw, int flags, unsigned len, int row, int col)
768 {
769 if (len != 0) {
770 TScreen *screen = TScreenOf(xw);
771 LineData *ld;
772 unsigned n;
773
774 ld = getLineData(screen, row);
775
776 if (((unsigned) col + len) > ld->lineSize)
777 len = (unsigned) (ld->lineSize - col);
778
779 if_OPT_WIDE_CHARS(screen, {
780 if (((unsigned) col + len) < ld->lineSize &&
781 ld->charData[col + (int) len] == HIDDEN_CHAR) {
782 len++;
783 }
784 if (col > 0 &&
785 ld->charData[col] == HIDDEN_CHAR) {
786 len++;
787 col--;
788 }
789 });
790
791 flags = (int) ((unsigned) flags | TERM_COLOR_FLAGS(xw));
792
793 for (n = 0; n < len; ++n) {
794 ld->charData[(unsigned) col + n] = (CharData) ' ';
795 }
796
797 FillIAttr(ld->attribs + col, (unsigned) flags, (size_t) len);
798
799 if_OPT_ISO_COLORS(screen, {
800 CellColor p = xtermColorPair(xw);
801 for (n = 0; n < len; ++n) {
802 ld->color[(unsigned) col + n] = p;
803 }
804 });
805 if_OPT_WIDE_CHARS(screen, {
806 size_t off;
807 for_each_combData(off, ld) {
808 memset(ld->combData[off] + col, 0, (size_t) len * sizeof(CharData));
809 }
810 });
811 }
812 }
813
814 /*
815 * Clear data in the screen-structure (no I/O).
816 * Check for wide-character damage as well, clearing the damaged cells.
817 */
818 void
ScrnClearCells(XtermWidget xw,int row,int col,unsigned len)819 ScrnClearCells(XtermWidget xw, int row, int col, unsigned len)
820 {
821 #if OPT_WIDE_CHARS
822 TScreen *screen = TScreenOf(xw);
823 #endif
824 int flags = 0;
825
826 if_OPT_WIDE_CHARS(screen, {
827 int kl;
828 int kr;
829
830 if (DamagedCells(screen, len, &kl, &kr, row, col)
831 && kr >= kl) {
832 ClearCells(xw, flags, (unsigned) (kr - kl + 1), row, kl);
833 }
834 });
835 ClearCells(xw, flags, len, row, col);
836 }
837
838 /*
839 * Disown the selection and repaint the area that is highlighted so it is no
840 * longer highlighted.
841 */
842 void
ScrnDisownSelection(XtermWidget xw)843 ScrnDisownSelection(XtermWidget xw)
844 {
845 if (ScrnHaveSelection(TScreenOf(xw))) {
846 TRACE(("ScrnDisownSelection\n"));
847 if (TScreenOf(xw)->keepSelection) {
848 UnhiliteSelection(xw);
849 } else {
850 DisownSelection(xw);
851 }
852 }
853 }
854
855 /*
856 * Writes str into buf at screen's current row and column. Characters are set
857 * to match flags.
858 */
859 void
ScrnWriteText(XtermWidget xw,IChar * str,unsigned flags,CellColor cur_fg_bg,unsigned length)860 ScrnWriteText(XtermWidget xw,
861 IChar *str,
862 unsigned flags,
863 CellColor cur_fg_bg,
864 unsigned length)
865 {
866 TScreen *screen = TScreenOf(xw);
867 LineData *ld;
868 IAttr *attrs;
869 int avail = MaxCols(screen) - screen->cur_col;
870 IChar *chars;
871 #if OPT_WIDE_CHARS
872 IChar starcol1;
873 #endif
874 unsigned n;
875 unsigned real_width = visual_width(str, length);
876
877 (void) cur_fg_bg; /* quiet compiler warnings when unused */
878
879 if (real_width + (unsigned) screen->cur_col > (unsigned) MaxCols(screen)) {
880 real_width = (unsigned) (MaxCols(screen) - screen->cur_col);
881 }
882
883 if (avail <= 0)
884 return;
885 if (length > (unsigned) avail)
886 length = (unsigned) avail;
887 if (length == 0 || real_width == 0)
888 return;
889
890 ld = getLineData(screen, screen->cur_row);
891
892 chars = ld->charData + screen->cur_col;
893 attrs = ld->attribs + screen->cur_col;
894
895 #if OPT_WIDE_CHARS
896 starcol1 = *chars;
897 #endif
898
899 /* write blanks if we're writing invisible text */
900 for (n = 0; n < length; ++n) {
901 if ((flags & INVISIBLE))
902 chars[n] = ' ';
903 else
904 chars[n] = str[n];
905 }
906
907 #if OPT_BLINK_TEXT
908 if ((flags & BLINK) && !(screen->blink_as_bold)) {
909 LineSetBlinked(ld);
910 }
911 #endif
912
913 if_OPT_WIDE_CHARS(screen, {
914
915 if (real_width != length) {
916 IChar *char1 = chars;
917 if (screen->cur_col
918 && starcol1 == HIDDEN_CHAR
919 && isWide((int) char1[-1])) {
920 char1[-1] = (CharData) ' ';
921 }
922 /* if we are overwriting the right hand half of a
923 wide character, make the other half vanish */
924 while (length) {
925 int ch = (int) str[0];
926
927 *char1++ = *str++;
928 length--;
929
930 if (isWide(ch)) {
931 *char1++ = (CharData) HIDDEN_CHAR;
932 }
933 }
934
935 if (*char1 == HIDDEN_CHAR
936 && char1[-1] == HIDDEN_CHAR) {
937 *char1 = (CharData) ' ';
938 }
939 /* if we are overwriting the left hand half of a
940 wide character, make the other half vanish */
941 } else {
942 if (screen->cur_col
943 && starcol1 == HIDDEN_CHAR
944 && isWide((int) chars[-1])) {
945 chars[-1] = (CharData) ' ';
946 }
947 /* if we are overwriting the right hand half of a
948 wide character, make the other half vanish */
949 if (chars[length] == HIDDEN_CHAR
950 && isWide((int) chars[length - 1])) {
951 chars[length] = (CharData) ' ';
952 }
953 }
954 });
955
956 flags &= ATTRIBUTES;
957 flags |= CHARDRAWN;
958 FillIAttr(attrs, flags, (size_t) real_width);
959
960 if_OPT_WIDE_CHARS(screen, {
961 size_t off;
962 for_each_combData(off, ld) {
963 memset(ld->combData[off] + screen->cur_col,
964 0,
965 real_width * sizeof(CharData));
966 }
967 });
968 if_OPT_ISO_COLORS(screen, {
969 unsigned j;
970 for (j = 0; j < real_width; ++j)
971 ld->color[screen->cur_col + (int) j] = cur_fg_bg;
972 });
973
974 #if OPT_WIDE_CHARS
975 screen->last_written_col = screen->cur_col + (int) real_width - 1;
976 screen->last_written_row = screen->cur_row;
977 #endif
978
979 TRACE(("text erasing cur_col=%d cur_row=%d real_width=%d\n",
980 screen->cur_col,
981 screen->cur_row,
982 real_width));
983 chararea_clear_displayed_graphics(screen,
984 screen->cur_col,
985 screen->cur_row,
986 (int) real_width, 1);
987
988 if_OPT_XMC_GLITCH(screen, {
989 Resolve_XMC(xw);
990 });
991
992 return;
993 }
994
995 /*
996 * Saves pointers to the n lines beginning at sb + where, and clears the lines
997 */
998 static void
ScrnClearLines(XtermWidget xw,ScrnBuf sb,int where,unsigned n,unsigned size)999 ScrnClearLines(XtermWidget xw, ScrnBuf sb, int where, unsigned n, unsigned size)
1000 {
1001 TScreen *screen = TScreenOf(xw);
1002 ScrnPtr *base;
1003 unsigned jump = scrnHeadSize(screen, 1);
1004 unsigned i;
1005 LineData *work;
1006 unsigned flags = TERM_COLOR_FLAGS(xw);
1007 #if OPT_ISO_COLORS
1008 unsigned j;
1009 #endif
1010
1011 TRACE(("ScrnClearLines(%s:where %d, n %d, size %d)\n",
1012 (sb == screen->saveBuf_index) ? "save" : "edit",
1013 where, n, size));
1014
1015 assert((int) n > 0);
1016 assert(size != 0);
1017
1018 /* save n lines at where */
1019 SaveLineData(sb, (unsigned) where, (size_t) n);
1020
1021 /* clear contents of old rows */
1022 base = screen->save_ptr;
1023 for (i = 0; i < n; ++i) {
1024 work = (LineData *) base;
1025 work->bufHead = 0;
1026 #if OPT_DEC_CHRSET
1027 SetLineDblCS(work, 0);
1028 #endif
1029
1030 memset(work->charData, 0, size * sizeof(CharData));
1031 if (TERM_COLOR_FLAGS(xw)) {
1032 FillIAttr(work->attribs, flags, (size_t) size);
1033 #if OPT_ISO_COLORS
1034 {
1035 CellColor p = xtermColorPair(xw);
1036 for (j = 0; j < size; ++j) {
1037 work->color[j] = p;
1038 }
1039 }
1040 #endif
1041 } else {
1042 FillIAttr(work->attribs, 0, (size_t) size);
1043 #if OPT_ISO_COLORS
1044 memset(work->color, 0, size * sizeof(work->color[0]));
1045 #endif
1046 }
1047 #if OPT_WIDE_CHARS
1048 if (screen->wide_chars) {
1049 size_t off;
1050
1051 for (off = 0; off < work->combSize; ++off) {
1052 memset(work->combData[off], 0, size * sizeof(CharData));
1053 }
1054 }
1055 #endif
1056 base = ScrnBufAddr(base, jump);
1057 }
1058
1059 TRACE(("clear lines erasing where=%d screen->savelines=%d n=%d screen->max_col=%d\n",
1060 where,
1061 screen->savelines,
1062 n,
1063 screen->max_col));
1064 /* FIXME: this looks wrong -- rcombs */
1065 chararea_clear_displayed_graphics(screen,
1066 where + screen->savelines,
1067 0,
1068 screen->max_col + 1,
1069 (int) n);
1070 }
1071
1072 /*
1073 * We're always ensured of having a visible buffer, but may not have saved
1074 * lines. Check the pointer that's sure to work.
1075 */
1076
1077 #define OkAllocBuf(screen) (screen->editBuf_index[0] != 0)
1078
1079 void
ScrnAllocBuf(XtermWidget xw)1080 ScrnAllocBuf(XtermWidget xw)
1081 {
1082 TScreen *screen = TScreenOf(xw);
1083
1084 if (!OkAllocBuf(screen)) {
1085 int nrows = MaxRows(screen);
1086
1087 TRACE(("ScrnAllocBuf %dx%d (%d)\n",
1088 nrows, MaxCols(screen), screen->savelines));
1089
1090 if (screen->savelines != 0) {
1091 /* for FIFO, we only need space for the index - addScrollback inits */
1092 screen->saveBuf_index = allocScrnHead(screen,
1093 (unsigned) (screen->savelines));
1094 } else {
1095 screen->saveBuf_index = 0;
1096 }
1097 screen->editBuf_index[0] = allocScrnBuf(xw,
1098 (unsigned) nrows,
1099 (unsigned) MaxCols(screen),
1100 &screen->editBuf_data[0]);
1101 screen->visbuf = VisBuf(screen);
1102 }
1103 return;
1104 }
1105
1106 size_t
ScrnPointers(TScreen * screen,size_t len)1107 ScrnPointers(TScreen *screen, size_t len)
1108 {
1109 size_t result = scrnHeadSize(screen, (unsigned) len);
1110
1111 if (result > screen->save_len) {
1112 if (screen->save_len)
1113 screen->save_ptr = (ScrnPtr *) realloc(screen->save_ptr, result);
1114 else
1115 screen->save_ptr = (ScrnPtr *) malloc(result);
1116 screen->save_len = len;
1117 if (screen->save_ptr == 0)
1118 SysError(ERROR_SAVE_PTR);
1119 }
1120 TRACE2(("ScrnPointers %ld ->%p\n", (long) len, screen->save_ptr));
1121 return result;
1122 }
1123
1124 /*
1125 * Inserts n blank lines at sb + where, treating last as a bottom margin.
1126 */
1127 void
ScrnInsertLine(XtermWidget xw,ScrnBuf sb,int last,int where,unsigned n)1128 ScrnInsertLine(XtermWidget xw, ScrnBuf sb, int last, int where, unsigned n)
1129 {
1130 TScreen *screen = TScreenOf(xw);
1131 unsigned size = (unsigned) MaxCols(screen);
1132
1133 TRACE(("ScrnInsertLine(last %d, where %d, n %d, size %d)\n",
1134 last, where, n, size));
1135
1136 assert(where >= 0);
1137 assert(last >= where);
1138
1139 assert((int) n > 0);
1140 assert(size != 0);
1141
1142 /* save n lines at bottom */
1143 ScrnClearLines(xw, sb, (last -= (int) n - 1), n, size);
1144 if (last < 0) {
1145 TRACE(("...remainder of screen is blank\n"));
1146 return;
1147 }
1148
1149 /*
1150 * WARNING, overlapping copy operation. Move down lines (pointers).
1151 *
1152 * +----|---------|--------+
1153 *
1154 * is copied in the array to:
1155 *
1156 * +--------|---------|----+
1157 */
1158 assert(last >= where);
1159 /*
1160 * This will never shift from the saveBuf to editBuf, so there is no need
1161 * to handle that case.
1162 */
1163 MoveLineData(sb,
1164 (unsigned) (where + (int) n),
1165 (unsigned) where,
1166 (unsigned) (last - where));
1167
1168 /* reuse storage for new lines at where */
1169 RestoreLineData(sb, (unsigned) where, n);
1170 }
1171
1172 /*
1173 * Deletes n lines at sb + where, treating last as a bottom margin.
1174 */
1175 void
ScrnDeleteLine(XtermWidget xw,ScrnBuf sb,int last,int where,unsigned n)1176 ScrnDeleteLine(XtermWidget xw, ScrnBuf sb, int last, int where, unsigned n)
1177 {
1178 TScreen *screen = TScreenOf(xw);
1179 unsigned size = (unsigned) MaxCols(screen);
1180
1181 TRACE(("ScrnDeleteLine(%s:last %d, where %d, n %d, size %d)\n",
1182 (sb == screen->saveBuf_index) ? "save" : "edit",
1183 last, where, n, size));
1184
1185 assert(where >= 0);
1186 assert(last >= where + (int) n - 1);
1187
1188 assert((int) n > 0);
1189 assert(size != 0);
1190
1191 /* move up lines */
1192 last -= ((int) n - 1);
1193
1194 if (inSaveBuf(screen, sb, where)) {
1195
1196 /* we shouldn't be editing the saveBuf, only scroll into it */
1197 assert(last >= screen->savelines);
1198
1199 if (sb != 0) {
1200 /* copy lines from editBuf to saveBuf (allocating as we go...) */
1201 saveEditBufLines(screen, n);
1202 }
1203
1204 /* adjust variables to fall-thru into changes only to editBuf */
1205 TRACE(("...adjusting variables, to work on editBuf alone\n"));
1206 last -= screen->savelines;
1207 where = 0;
1208 sb = screen->visbuf;
1209 }
1210
1211 /*
1212 * Scroll the visible buffer (editBuf).
1213 */
1214 ScrnClearLines(xw, sb, where, n, size);
1215
1216 MoveLineData(sb,
1217 (unsigned) where,
1218 (unsigned) (where + (int) n),
1219 (size_t) (last - where));
1220
1221 /* reuse storage for new bottom lines */
1222 RestoreLineData(sb, (unsigned) last, n);
1223 }
1224
1225 /*
1226 * Inserts n blanks in screen at current row, col. Size is the size of each
1227 * row.
1228 */
1229 void
ScrnInsertChar(XtermWidget xw,unsigned n)1230 ScrnInsertChar(XtermWidget xw, unsigned n)
1231 {
1232 #define MemMove(data) \
1233 for (j = last; j >= (col + (int) n); --j) \
1234 data[j] = data[j - (int) n]
1235
1236 TScreen *screen = TScreenOf(xw);
1237 int first = ScrnLeftMargin(xw);
1238 int last = ScrnRightMargin(xw);
1239 int row = screen->cur_row;
1240 int col = screen->cur_col;
1241 int j;
1242 LineData *ld;
1243
1244 if (col < first || col > last) {
1245 TRACE(("ScrnInsertChar - col %d outside [%d..%d]\n", col, first, last));
1246 return;
1247 } else if (last < (col + (int) n)) {
1248 n = (unsigned) (last + 1 - col);
1249 }
1250
1251 assert(screen->cur_col >= 0);
1252 assert(screen->cur_row >= 0);
1253 assert((int) n >= 0);
1254 assert((last + 1) >= (int) n);
1255
1256 if_OPT_WIDE_CHARS(screen, {
1257 int xx = screen->cur_row;
1258 int kl;
1259 int kr = screen->cur_col;
1260 if (DamagedCells(screen, n, &kl, (int *) 0, xx, kr) && kr > kl) {
1261 ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl);
1262 }
1263 kr = last - (int) n + 1;
1264 if (DamagedCells(screen, n, &kl, (int *) 0, xx, kr) && kr > kl) {
1265 ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl);
1266 }
1267 });
1268
1269 if ((ld = getLineData(screen, row)) != 0) {
1270 MemMove(ld->charData);
1271 MemMove(ld->attribs);
1272
1273 if_OPT_ISO_COLORS(screen, {
1274 MemMove(ld->color);
1275 });
1276 if_OPT_WIDE_CHARS(screen, {
1277 size_t off;
1278 for_each_combData(off, ld) {
1279 MemMove(ld->combData[off]);
1280 }
1281 });
1282 }
1283 ClearCells(xw, CHARDRAWN, n, row, col);
1284
1285 #undef MemMove
1286 }
1287
1288 /*
1289 * Deletes n characters at current row, col.
1290 */
1291 void
ScrnDeleteChar(XtermWidget xw,unsigned n)1292 ScrnDeleteChar(XtermWidget xw, unsigned n)
1293 {
1294 #define MemMove(data) \
1295 for (j = col; j <= last - (int) n; ++j) \
1296 data[j] = data[j + (int) n]
1297
1298 TScreen *screen = TScreenOf(xw);
1299 int first = ScrnLeftMargin(xw);
1300 int last = ScrnRightMargin(xw) + 1;
1301 int row = screen->cur_row;
1302 int col = screen->cur_col;
1303 int j;
1304 LineData *ld;
1305
1306 if (col < first || col > last) {
1307 TRACE(("ScrnDeleteChar - col %d outside [%d..%d]\n", col, first, last));
1308 return;
1309 } else if (last <= (col + (int) n)) {
1310 n = (unsigned) (last - col);
1311 }
1312
1313 assert(screen->cur_col >= 0);
1314 assert(screen->cur_row >= 0);
1315 assert((int) n >= 0);
1316 assert(last >= (int) n);
1317
1318 if_OPT_WIDE_CHARS(screen, {
1319 int kl;
1320 int kr;
1321 if (DamagedCells(screen, n, &kl, &kr,
1322 screen->cur_row,
1323 screen->cur_col))
1324 ClearCells(xw, 0, (unsigned) (kr - kl + 1), row, kl);
1325 });
1326
1327 if ((ld = getLineData(screen, row)) != 0) {
1328 MemMove(ld->charData);
1329 MemMove(ld->attribs);
1330
1331 if_OPT_ISO_COLORS(screen, {
1332 MemMove(ld->color);
1333 });
1334 if_OPT_WIDE_CHARS(screen, {
1335 size_t off;
1336 for_each_combData(off, ld) {
1337 MemMove(ld->combData[off]);
1338 }
1339 });
1340 LineClrWrapped(ld);
1341 ShowWrapMarks(xw, row, ld);
1342 }
1343 ClearCells(xw, 0, n, row, (last - (int) n));
1344
1345 #undef MemMove
1346 }
1347
1348 #define WhichMarkGC(set) (set ? 1 : 0)
1349 #define WhichMarkColor(set) T_COLOR(screen, (set ? TEXT_CURSOR : TEXT_BG))
1350
1351 void
FreeMarkGCs(XtermWidget xw)1352 FreeMarkGCs(XtermWidget xw)
1353 {
1354 TScreen *const screen = TScreenOf(xw);
1355 Display *const display = screen->display;
1356 VTwin *vwin = WhichVWin(screen);
1357 int which;
1358
1359 for (which = 0; which < 2; ++which) {
1360 if (vwin->marker_gc[which] != NULL) {
1361 XFreeGC(display, vwin->marker_gc[which]);
1362 vwin->marker_gc[which] = NULL;
1363 }
1364 }
1365 }
1366
1367 static GC
MakeMarkGC(XtermWidget xw,Bool set)1368 MakeMarkGC(XtermWidget xw, Bool set)
1369 {
1370 TScreen *const screen = TScreenOf(xw);
1371 VTwin *vwin = WhichVWin(screen);
1372 int which = WhichMarkGC(set);
1373
1374 if (vwin->marker_gc[which] == NULL) {
1375 Display *const display = screen->display;
1376 Window const drawable = VDrawable(screen);
1377 XGCValues xgcv;
1378 XtGCMask mask = GCForeground;
1379
1380 memset(&xgcv, 0, sizeof(xgcv));
1381 xgcv.foreground = WhichMarkColor(set);
1382 vwin->marker_gc[which] = XCreateGC(display,
1383 drawable,
1384 mask,
1385 &xgcv);
1386 }
1387 return vwin->marker_gc[which];
1388 }
1389
1390 /*
1391 * This is useful for debugging both xterm and applications that may manipulate
1392 * its line-wrapping state.
1393 */
1394 void
ShowWrapMarks(XtermWidget xw,int row,CLineData * ld)1395 ShowWrapMarks(XtermWidget xw, int row, CLineData *ld)
1396 {
1397 TScreen *screen = TScreenOf(xw);
1398 if (screen->show_wrap_marks) {
1399 Bool set = (Bool) LineTstWrapped(ld);
1400 int y = row * FontHeight(screen) + screen->border;
1401 int x = LineCursorX(screen, ld, screen->max_col + 1);
1402
1403 TRACE2(("ShowWrapMarks %d:%s\n", row, BtoS(set)));
1404
1405 XFillRectangle(screen->display,
1406 VDrawable(screen),
1407 MakeMarkGC(xw, set),
1408 x, y,
1409 (unsigned) screen->border,
1410 (unsigned) FontHeight(screen));
1411 }
1412 }
1413
1414 /*
1415 * Repaints the area enclosed by the parameters.
1416 * Requires: (toprow, leftcol), (toprow + nrows, leftcol + ncols) are
1417 * coordinates of characters in screen;
1418 * nrows and ncols positive.
1419 * all dimensions are based on single-characters.
1420 */
1421 void
ScrnRefresh(XtermWidget xw,int toprow,int leftcol,int nrows,int ncols,Bool force)1422 ScrnRefresh(XtermWidget xw,
1423 int toprow,
1424 int leftcol,
1425 int nrows,
1426 int ncols,
1427 Bool force) /* ... leading/trailing spaces */
1428 {
1429 TScreen *screen = TScreenOf(xw);
1430 XTermDraw params;
1431 CLineData *ld;
1432 int y = toprow * FontHeight(screen) + screen->border;
1433 int row;
1434 int maxrow = toprow + nrows - 1;
1435 int scrollamt = screen->scroll_amt;
1436 unsigned gc_changes = 0;
1437 #ifdef __CYGWIN__
1438 static char first_time = 1;
1439 #endif
1440 static int recurse = 0;
1441 #if OPT_WIDE_ATTRS
1442 unsigned old_attrs = xw->flags;
1443 #endif
1444
1445 TRACE(("ScrnRefresh top %d (%d,%d) - (%d,%d)%s " TRACE_L "\n",
1446 screen->topline, toprow, leftcol,
1447 nrows, ncols,
1448 force ? " force" : ""));
1449
1450 ++recurse;
1451
1452 if (screen->cursorp.col >= leftcol
1453 && screen->cursorp.col <= (leftcol + ncols - 1)
1454 && screen->cursorp.row >= ROW2INX(screen, toprow)
1455 && screen->cursorp.row <= ROW2INX(screen, maxrow))
1456 screen->cursor_state = OFF;
1457
1458 for (row = toprow; row <= maxrow; y += FontHeight(screen), row++) {
1459 #if OPT_ISO_COLORS
1460 CellColor *fb = 0;
1461 #define ColorOf(col) (fb ? fb[col] : initCColor)
1462 #endif
1463 #if OPT_WIDE_CHARS
1464 int wideness = 0;
1465 #endif
1466 #define BLANK_CEL(cell) (chars[cell] == ' ')
1467 IChar *chars;
1468 const IAttr *attrs;
1469 int col = leftcol;
1470 int maxcol = leftcol + ncols - 1;
1471 int hi_col = maxcol;
1472 int lastind;
1473 unsigned flags;
1474 unsigned test;
1475 CellColor fg_bg = initCColor;
1476 Pixel fg = 0, bg = 0;
1477 int x;
1478 GC gc;
1479 Bool hilite;
1480
1481 (void) fg;
1482 (void) bg;
1483 #if !OPT_ISO_COLORS
1484 fg_bg = 0;
1485 #endif
1486
1487 if (row < screen->top_marg || row > screen->bot_marg)
1488 lastind = row;
1489 else
1490 lastind = row - scrollamt;
1491
1492 if (lastind < 0 || lastind > screen->max_row)
1493 continue;
1494
1495 TRACE2(("ScrnRefresh row=%d lastind=%d ->%d\n",
1496 row, lastind, ROW2INX(screen, lastind)));
1497
1498 if ((ld = getLineData(screen, ROW2INX(screen, lastind))) == 0
1499 || ld->charData == 0
1500 || ld->attribs == 0) {
1501 break;
1502 }
1503
1504 ShowWrapMarks(xw, lastind, ld);
1505
1506 if (maxcol >= (int) ld->lineSize) {
1507 maxcol = ld->lineSize - 1;
1508 hi_col = maxcol;
1509 }
1510
1511 chars = ld->charData;
1512 attrs = ld->attribs;
1513
1514 if_OPT_WIDE_CHARS(screen, {
1515 /* This fixes an infinite recursion bug, that leads
1516 to display anomalies. It seems to be related to
1517 problems with the selection. */
1518 if (recurse < 3) {
1519 /* adjust to redraw all of a widechar if we just wanted
1520 to draw the right hand half */
1521 if (leftcol > 0 &&
1522 chars[leftcol] == HIDDEN_CHAR &&
1523 isWide((int) chars[leftcol - 1])) {
1524 leftcol--;
1525 ncols++;
1526 col = leftcol;
1527 }
1528 } else {
1529 xtermWarning("Unexpected recursion drawing hidden characters.\n");
1530 }
1531 });
1532
1533 if (row < screen->startH.row || row > screen->endH.row ||
1534 (row == screen->startH.row && maxcol < screen->startH.col) ||
1535 (row == screen->endH.row && col >= screen->endH.col)) {
1536 #if OPT_DEC_CHRSET
1537 /*
1538 * Temporarily change dimensions to double-sized characters so
1539 * we can reuse the recursion on this function.
1540 */
1541 if (CSET_DOUBLE(GetLineDblCS(ld))) {
1542 col /= 2;
1543 maxcol /= 2;
1544 }
1545 #endif
1546 /*
1547 * If row does not intersect selection; don't hilite blanks.
1548 */
1549 if (!force) {
1550 while (col <= maxcol && (attrs[col] & ~BOLD) == 0 &&
1551 BLANK_CEL(col))
1552 col++;
1553
1554 while (col <= maxcol && (attrs[maxcol] & ~BOLD) == 0 &&
1555 BLANK_CEL(maxcol))
1556 maxcol--;
1557 }
1558 #if OPT_DEC_CHRSET
1559 if (CSET_DOUBLE(GetLineDblCS(ld))) {
1560 col *= 2;
1561 maxcol *= 2;
1562 }
1563 #endif
1564 hilite = False;
1565 } else {
1566 /* row intersects selection; split into pieces of single type */
1567 if (row == screen->startH.row && col < screen->startH.col) {
1568 ScrnRefresh(xw, row, col, 1, screen->startH.col - col,
1569 force);
1570 col = screen->startH.col;
1571 }
1572 if (row == screen->endH.row && maxcol >= screen->endH.col) {
1573 ScrnRefresh(xw, row, screen->endH.col, 1,
1574 maxcol - screen->endH.col + 1, force);
1575 maxcol = screen->endH.col - 1;
1576 }
1577
1578 /*
1579 * If we're highlighting because the user is doing cut/paste,
1580 * trim the trailing blanks from the highlighted region so we're
1581 * showing the actual extent of the text that'll be cut. If
1582 * we're selecting a blank line, we'll highlight one column
1583 * anyway.
1584 *
1585 * We don't do this if the mouse-hilite mode is set because that
1586 * would be too confusing.
1587 *
1588 * The default if the highlightSelection resource isn't set will
1589 * highlight the whole width of the terminal, which is easy to
1590 * see, but harder to use (because trailing blanks aren't as
1591 * apparent).
1592 */
1593 if (screen->highlight_selection
1594 && screen->send_mouse_pos != VT200_HIGHLIGHT_MOUSE) {
1595 hi_col = screen->max_col;
1596 while (hi_col > 0 && !(attrs[hi_col] & CHARDRAWN))
1597 hi_col--;
1598 }
1599
1600 /* remaining piece should be hilited */
1601 hilite = True;
1602 }
1603
1604 if (col > maxcol)
1605 continue;
1606
1607 /*
1608 * Go back to double-sized character dimensions if the line has
1609 * double-width characters. Note that 'hi_col' is already in the
1610 * right units.
1611 */
1612 if_OPT_DEC_CHRSET({
1613 if (CSET_DOUBLE(GetLineDblCS(ld))) {
1614 col /= 2;
1615 maxcol /= 2;
1616 }
1617 });
1618
1619 flags = attrs[col];
1620
1621 if_OPT_WIDE_CHARS(screen, {
1622 wideness = isWide((int) chars[col]);
1623 });
1624
1625 if_OPT_ISO_COLORS(screen, {
1626 fb = ld->color;
1627 fg_bg = ColorOf(col);
1628 fg = extract_fg(xw, fg_bg, flags);
1629 bg = extract_bg(xw, fg_bg, flags);
1630 });
1631
1632 #if OPT_WIDE_ATTRS
1633 old_attrs = xtermUpdateItalics(xw, flags, old_attrs);
1634 #endif
1635 gc = updatedXtermGC(xw, flags, fg_bg, hilite);
1636 gc_changes |= (flags & (FG_COLOR | BG_COLOR));
1637
1638 x = LineCursorX(screen, ld, col);
1639 lastind = col;
1640
1641 for (; col <= maxcol; col++) {
1642 if (
1643 #if OPT_WIDE_CHARS
1644 (chars[col] != HIDDEN_CHAR) &&
1645 #endif
1646 ((attrs[col] != flags)
1647 || (hilite && (col > hi_col))
1648 #if OPT_ISO_COLORS
1649 || ((flags & FG_COLOR)
1650 && (extract_fg(xw, ColorOf(col), attrs[col]) != fg))
1651 || ((flags & BG_COLOR)
1652 && (extract_bg(xw, ColorOf(col), attrs[col]) != bg))
1653 #endif
1654 #if OPT_WIDE_CHARS
1655 || (isWide((int) chars[col]) != wideness)
1656 #endif
1657 )
1658 ) {
1659 assert(col >= lastind);
1660 TRACE(("ScrnRefresh looping drawXtermText %d..%d:%s\n",
1661 lastind, col,
1662 visibleIChars((&chars[lastind]),
1663 (unsigned) (col - lastind))));
1664
1665 test = flags;
1666 checkVeryBoldColors(test, fg);
1667
1668 /* *INDENT-EQLS* */
1669 params.xw = xw;
1670 params.attr_flags = (test & DRAWX_MASK);
1671 params.draw_flags = 0;
1672 params.this_chrset = GetLineDblCS(ld);
1673 params.real_chrset = CSET_SWL;
1674 params.on_wide = 0;
1675
1676 x = drawXtermText(¶ms,
1677 gc, x, y,
1678 &chars[lastind],
1679 (unsigned) (col - lastind));
1680
1681 if_OPT_WIDE_CHARS(screen, {
1682 int i;
1683 size_t off;
1684
1685 params.draw_flags = NOBACKGROUND;
1686
1687 for_each_combData(off, ld) {
1688 IChar *com_off = ld->combData[off];
1689
1690 for (i = lastind; i < col; i++) {
1691 int my_x = LineCursorX(screen, ld, i);
1692 IChar base = chars[i];
1693
1694 if ((params.on_wide = isWide((int) base)))
1695 my_x = LineCursorX(screen, ld, i - 1);
1696
1697 if (com_off[i] != 0)
1698 drawXtermText(¶ms,
1699 gc, my_x, y,
1700 com_off + i,
1701 1);
1702 }
1703 }
1704 });
1705
1706 resetXtermGC(xw, flags, hilite);
1707
1708 lastind = col;
1709
1710 if (hilite && (col > hi_col))
1711 hilite = False;
1712
1713 flags = attrs[col];
1714 if_OPT_ISO_COLORS(screen, {
1715 fg_bg = ColorOf(col);
1716 fg = extract_fg(xw, fg_bg, flags);
1717 bg = extract_bg(xw, fg_bg, flags);
1718 });
1719 if_OPT_WIDE_CHARS(screen, {
1720 wideness = isWide((int) chars[col]);
1721 });
1722
1723 #if OPT_WIDE_ATTRS
1724 old_attrs = xtermUpdateItalics(xw, flags, old_attrs);
1725 #endif
1726 gc = updatedXtermGC(xw, flags, fg_bg, hilite);
1727 gc_changes |= (flags & (FG_COLOR | BG_COLOR));
1728 }
1729
1730 if (chars[col] == 0) {
1731 chars[col] = ' ';
1732 }
1733 }
1734
1735 assert(col >= lastind);
1736 TRACE(("ScrnRefresh calling drawXtermText %d..%d:%s\n",
1737 lastind, col,
1738 visibleIChars(&chars[lastind], (unsigned) (col - lastind))));
1739
1740 test = flags;
1741 checkVeryBoldColors(test, fg);
1742
1743 /* *INDENT-EQLS* */
1744 params.xw = xw;
1745 params.attr_flags = (test & DRAWX_MASK);
1746 params.draw_flags = 0;
1747 params.this_chrset = GetLineDblCS(ld);
1748 params.real_chrset = CSET_SWL;
1749 params.on_wide = 0;
1750
1751 drawXtermText(¶ms,
1752 gc, x, y,
1753 &chars[lastind],
1754 (unsigned) (col - lastind));
1755
1756 if_OPT_WIDE_CHARS(screen, {
1757 int i;
1758 size_t off;
1759
1760 params.draw_flags = NOBACKGROUND;
1761
1762 for_each_combData(off, ld) {
1763 IChar *com_off = ld->combData[off];
1764
1765 for (i = lastind; i < col; i++) {
1766 int my_x = LineCursorX(screen, ld, i);
1767 int base = (int) chars[i];
1768
1769 if ((params.on_wide = isWide(base)))
1770 my_x = LineCursorX(screen, ld, i - 1);
1771
1772 if (com_off[i] != 0)
1773 drawXtermText(¶ms,
1774 gc, my_x, y,
1775 com_off + i,
1776 1);
1777 }
1778 }
1779 });
1780
1781 resetXtermGC(xw, flags, hilite);
1782 }
1783
1784 refresh_displayed_graphics(xw, leftcol, toprow, ncols, nrows);
1785
1786 /*
1787 * If we're in color mode, reset the various GC's to the current
1788 * screen foreground and background so that other functions (e.g.,
1789 * ClearRight) will get the correct colors.
1790 */
1791 #if OPT_WIDE_ATTRS
1792 (void) xtermUpdateItalics(xw, xw->flags, old_attrs);
1793 #endif
1794 if_OPT_ISO_COLORS(screen, {
1795 if (gc_changes & FG_COLOR)
1796 SGR_Foreground(xw, xw->cur_foreground);
1797 if (gc_changes & BG_COLOR)
1798 SGR_Background(xw, xw->cur_background);
1799 });
1800
1801 #if defined(__CYGWIN__) && defined(TIOCSWINSZ)
1802 if (first_time == 1) {
1803 first_time = 0;
1804 update_winsize(screen->respond, nrows, ncols, xw->core.height, xw->core.width);
1805 }
1806 #endif
1807 recurse--;
1808
1809 TRACE((TRACE_R " ScrnRefresh\n"));
1810 return;
1811 }
1812
1813 /*
1814 * Call this wrapper to ScrnRefresh() when the data has changed. If the
1815 * refresh region overlaps the selection, we will release the primary selection.
1816 */
1817 void
ScrnUpdate(XtermWidget xw,int toprow,int leftcol,int nrows,int ncols,Bool force)1818 ScrnUpdate(XtermWidget xw,
1819 int toprow,
1820 int leftcol,
1821 int nrows,
1822 int ncols,
1823 Bool force) /* ... leading/trailing spaces */
1824 {
1825 TScreen *screen = TScreenOf(xw);
1826
1827 if (ScrnHaveSelection(screen)
1828 && (toprow <= screen->endH.row)
1829 && (toprow + nrows - 1 >= screen->startH.row)) {
1830 ScrnDisownSelection(xw);
1831 }
1832 ScrnRefresh(xw, toprow, leftcol, nrows, ncols, force);
1833 }
1834
1835 /*
1836 * Sets the rows first though last of the buffer of screen to spaces.
1837 * Requires first <= last; first, last are rows of screen->buf.
1838 */
1839 void
ClearBufRows(XtermWidget xw,int first,int last)1840 ClearBufRows(XtermWidget xw,
1841 int first,
1842 int last)
1843 {
1844 TScreen *screen = TScreenOf(xw);
1845 unsigned len = (unsigned) MaxCols(screen);
1846 int row;
1847
1848 TRACE(("ClearBufRows %d..%d\n", first, last));
1849 for (row = first; row <= last; row++) {
1850 LineData *ld = getLineData(screen, row);
1851 if (ld != 0) {
1852 if_OPT_DEC_CHRSET({
1853 /* clearing the whole row resets the doublesize characters */
1854 SetLineDblCS(ld, CSET_SWL);
1855 });
1856 LineClrWrapped(ld);
1857 ShowWrapMarks(xw, row, ld);
1858 ClearCells(xw, 0, len, row, 0);
1859 }
1860 }
1861 }
1862
1863 /*
1864 Resizes screen:
1865 1. If new window would have fractional characters, sets window size so as to
1866 discard fractional characters and returns -1.
1867 Minimum screen size is 1 X 1.
1868 Note that this causes another ExposeWindow event.
1869 2. Enlarges screen->buf if necessary. New space is appended to the bottom
1870 and to the right
1871 3. Reduces screen->buf if necessary. Old space is removed from the bottom
1872 and from the right
1873 4. Cursor is positioned as closely to its former position as possible
1874 5. Sets screen->max_row and screen->max_col to reflect new size
1875 6. Maintains the inner border (and clears the border on the screen).
1876 7. Clears origin mode and sets scrolling region to be entire screen.
1877 8. Returns 0
1878 */
1879 int
ScreenResize(XtermWidget xw,int width,int height,unsigned * flags)1880 ScreenResize(XtermWidget xw,
1881 int width,
1882 int height,
1883 unsigned *flags)
1884 {
1885 TScreen *screen = TScreenOf(xw);
1886 int rows, cols;
1887 const int border = 2 * screen->border;
1888 int move_down_by = 0;
1889
1890 TRACE(("ScreenResize %dx%d border 2*%d font %dx%d\n",
1891 height, width, screen->border,
1892 FontHeight(screen), FontWidth(screen)));
1893
1894 assert(width > 0);
1895 assert(height > 0);
1896
1897 if (screen->is_running) {
1898 /* clear the right and bottom internal border because of NorthWest
1899 gravity might have left junk on the right and bottom edges */
1900 if (width >= (int) FullWidth(screen)) {
1901 xtermClear2(xw,
1902 FullWidth(screen), 0, /* right edge */
1903 0, (unsigned) height); /* from top to bottom */
1904 }
1905 if (height >= (int) FullHeight(screen)) {
1906 xtermClear2(xw,
1907 0, FullHeight(screen), /* bottom */
1908 (unsigned) width, 0); /* all across the bottom */
1909 }
1910 }
1911
1912 TRACE(("...computing rows/cols: %.2f %.2f\n",
1913 (double) (height - border) / FontHeight(screen),
1914 (double) (width - border - ScrollbarWidth(screen)) / FontWidth(screen)));
1915
1916 rows = (height - border) / FontHeight(screen);
1917 cols = (width - border - ScrollbarWidth(screen)) / FontWidth(screen);
1918 if (rows < 1)
1919 rows = 1;
1920 if (cols < 1)
1921 cols = 1;
1922
1923 /* update buffers if the screen has changed size */
1924 if (MaxRows(screen) != rows || MaxCols(screen) != cols) {
1925 int delta_rows = rows - MaxRows(screen);
1926 #if OPT_TRACE
1927 int delta_cols = cols - MaxCols(screen);
1928 #endif
1929
1930 TRACE(("...ScreenResize chars %dx%d delta %dx%d\n",
1931 rows, cols, delta_rows, delta_cols));
1932
1933 if (screen->is_running) {
1934 if (screen->cursor_state)
1935 HideCursor(xw);
1936
1937 /*
1938 * The non-visible buffer is simple, since we will not copy data
1939 * to/from the saved-lines. Do that first.
1940 */
1941 if (screen->editBuf_index[!screen->whichBuf]) {
1942 (void) Reallocate(xw,
1943 &screen->editBuf_index[!screen->whichBuf],
1944 &screen->editBuf_data[!screen->whichBuf],
1945 (unsigned) rows,
1946 (unsigned) cols,
1947 (unsigned) MaxRows(screen));
1948 }
1949
1950 /*
1951 * The save-lines buffer may change width, but will not change its
1952 * height. Deal with the cases where we copy data to/from the
1953 * saved-lines buffer.
1954 */
1955 if (GravityIsSouthWest(xw)
1956 && delta_rows
1957 && screen->saveBuf_index != 0) {
1958
1959 if (delta_rows < 0) {
1960 unsigned move_up = (unsigned) (-delta_rows);
1961 int amount = ((MaxRows(screen) - (int) move_up - 1)
1962 - screen->cur_row);
1963
1964 if (amount < 0) {
1965 /* move line-data from visible-buffer to save-buffer */
1966 saveEditBufLines(screen, (unsigned) -amount);
1967 move_down_by = amount;
1968 } else {
1969 move_down_by = 0;
1970 }
1971
1972 /* decrease size of visible-buffer */
1973 (void) Reallocate(xw,
1974 &screen->editBuf_index[screen->whichBuf],
1975 &screen->editBuf_data[screen->whichBuf],
1976 (unsigned) rows,
1977 (unsigned) cols,
1978 (unsigned) MaxRows(screen));
1979 TRACE_SCRNBUF("reallocEDIT",
1980 screen,
1981 screen->editBuf_index[screen->whichBuf],
1982 rows);
1983 } else {
1984 unsigned move_down = (unsigned) delta_rows;
1985 long unsave_fifo;
1986 ScrnBuf dst;
1987 int amount;
1988
1989 if ((int) move_down > screen->savedlines) {
1990 move_down = (unsigned) screen->savedlines;
1991 }
1992 move_down_by = (int) move_down;
1993 amount = rows - (int) move_down;
1994
1995 /* increase size of visible-buffer */
1996 (void) Reallocate(xw,
1997 &screen->editBuf_index[screen->whichBuf],
1998 &screen->editBuf_data[screen->whichBuf],
1999 (unsigned) rows,
2000 (unsigned) cols,
2001 (unsigned) MaxRows(screen));
2002
2003 dst = screen->editBuf_index[screen->whichBuf];
2004 TRACE_SCRNBUF("reallocEDIT", screen, dst, rows);
2005
2006 TRACE(("...%smoving pointers in editBuf (compare %d %d)\n",
2007 (amount > 0
2008 ? ""
2009 : "SKIP "),
2010 rows,
2011 move_down));
2012 if (amount > 0) {
2013 /* shift lines in visible-buffer to make room */
2014 SaveLineData(dst, (unsigned) amount, (size_t) move_down);
2015
2016 MoveLineData(dst,
2017 move_down,
2018 0,
2019 (unsigned) amount);
2020
2021 TRACE(("...reuse %d lines storage in editBuf\n", move_down));
2022 RestoreLineData(dst,
2023 0,
2024 move_down);
2025
2026 TRACE_SCRNBUF("shifted", screen, dst, rows);
2027 }
2028
2029 /* copy line-data from save-buffer to visible-buffer */
2030 unsaveEditBufLines(screen, dst, move_down);
2031 TRACE_SCRNBUF("copied", screen, dst, rows);
2032
2033 unsave_fifo = (long) move_down;
2034 if (screen->saved_fifo < (int) unsave_fifo)
2035 unsave_fifo = screen->saved_fifo;
2036
2037 /* free up storage in fifo from the copied lines */
2038 while (unsave_fifo-- > 0) {
2039 deleteScrollback(screen);
2040 }
2041
2042 /* recover storage in save-buffer */
2043 }
2044 } else {
2045 (void) Reallocate(xw,
2046 &screen->editBuf_index[screen->whichBuf],
2047 &screen->editBuf_data[screen->whichBuf],
2048 (unsigned) rows,
2049 (unsigned) cols,
2050 (unsigned) MaxRows(screen));
2051 }
2052
2053 screen->visbuf = VisBuf(screen);
2054 }
2055
2056 AdjustSavedCursor(xw, move_down_by);
2057 set_max_row(screen, screen->max_row + delta_rows);
2058 set_max_col(screen, cols - 1);
2059
2060 if (screen->is_running) {
2061 if (GravityIsSouthWest(xw)) {
2062 screen->savedlines -= move_down_by;
2063 if (screen->savedlines < 0)
2064 screen->savedlines = 0;
2065 if (screen->savedlines > screen->savelines)
2066 screen->savedlines = screen->savelines;
2067 if (screen->topline < -screen->savedlines)
2068 screen->topline = -screen->savedlines;
2069 set_cur_row(screen, screen->cur_row + move_down_by);
2070 screen->cursorp.row += move_down_by;
2071 ScrollSelection(screen, move_down_by, True);
2072 }
2073 }
2074
2075 /* adjust scrolling region */
2076 resetMargins(xw);
2077 UIntClr(*flags, ORIGIN);
2078
2079 if (screen->cur_row > screen->max_row)
2080 set_cur_row(screen, screen->max_row);
2081 if (screen->cur_col > screen->max_col)
2082 set_cur_col(screen, screen->max_col);
2083
2084 screen->fullVwin.height = height - border;
2085 screen->fullVwin.width = width - border - screen->fullVwin.sb_info.width;
2086
2087 scroll_displayed_graphics(xw, -move_down_by);
2088 } else if (FullHeight(screen) == height && FullWidth(screen) == width)
2089 return (0); /* nothing has changed at all */
2090
2091 screen->fullVwin.fullheight = (Dimension) height;
2092 screen->fullVwin.fullwidth = (Dimension) width;
2093
2094 ResizeScrollBar(xw);
2095 ResizeSelection(screen, rows, cols);
2096
2097 #ifndef NO_ACTIVE_ICON
2098 if (screen->iconVwin.window) {
2099 XWindowChanges changes;
2100 screen->iconVwin.width =
2101 MaxCols(screen) * screen->iconVwin.f_width;
2102
2103 screen->iconVwin.height =
2104 MaxRows(screen) * screen->iconVwin.f_height;
2105
2106 changes.width = screen->iconVwin.fullwidth =
2107 (Dimension) ((unsigned) screen->iconVwin.width
2108 + 2 * xw->misc.icon_border_width);
2109
2110 changes.height = screen->iconVwin.fullheight =
2111 (Dimension) ((unsigned) screen->iconVwin.height
2112 + 2 * xw->misc.icon_border_width);
2113
2114 changes.border_width = (int) xw->misc.icon_border_width;
2115
2116 TRACE(("resizing icon window %dx%d\n", changes.height, changes.width));
2117 XConfigureWindow(XtDisplay(xw), screen->iconVwin.window,
2118 CWWidth | CWHeight | CWBorderWidth, &changes);
2119 }
2120 #endif /* NO_ACTIVE_ICON */
2121
2122 #ifdef TTYSIZE_STRUCT
2123 if (update_winsize(screen->respond, rows, cols, height, width) == 0) {
2124 #if defined(SIGWINCH) && defined(TIOCGPGRP)
2125 if (screen->pid > 1) {
2126 int pgrp;
2127
2128 TRACE(("getting process-group\n"));
2129 if (ioctl(screen->respond, TIOCGPGRP, &pgrp) != -1) {
2130 TRACE(("sending SIGWINCH to process group %d\n", pgrp));
2131 kill_process_group(pgrp, SIGWINCH);
2132 }
2133 }
2134 #endif /* SIGWINCH */
2135 }
2136 #else
2137 TRACE(("ScreenResize cannot do anything to pty\n"));
2138 #endif /* TTYSIZE_STRUCT */
2139 return (0);
2140 }
2141
2142 /*
2143 * Return true if any character cell starting at [row,col], for len-cells is
2144 * nonnull.
2145 */
2146 Bool
non_blank_line(TScreen * screen,int row,int col,int len)2147 non_blank_line(TScreen *screen,
2148 int row,
2149 int col,
2150 int len)
2151 {
2152 int i;
2153 Bool found = False;
2154 LineData *ld = getLineData(screen, row);
2155
2156 if (ld != 0) {
2157 for (i = col; i < len; i++) {
2158 if (ld->charData[i]) {
2159 found = True;
2160 break;
2161 }
2162 }
2163 }
2164 return found;
2165 }
2166
2167 /*
2168 * Limit/map rectangle parameters.
2169 */
2170 #define minRectRow(screen) (getMinRow(screen) + 1)
2171 #define minRectCol(screen) (getMinCol(screen) + 1)
2172 #define maxRectRow(screen) (getMaxRow(screen) + 1)
2173 #define maxRectCol(screen) (getMaxCol(screen) + 1)
2174
2175 static int
limitedParseRow(XtermWidget xw,int row,int err)2176 limitedParseRow(XtermWidget xw, int row, int err)
2177 {
2178 TScreen *screen = TScreenOf(xw);
2179 int min_row = minRectRow(screen);
2180 int max_row = maxRectRow(screen) + err;
2181
2182 if (xw->flags & ORIGIN)
2183 row += screen->top_marg;
2184
2185 if (row < min_row)
2186 row = min_row;
2187 else if (row > max_row)
2188 row = max_row;
2189
2190 return row;
2191 }
2192
2193 static int
limitedParseCol(XtermWidget xw,int col,int err)2194 limitedParseCol(XtermWidget xw, int col, int err)
2195 {
2196 TScreen *screen = TScreenOf(xw);
2197 int min_col = minRectCol(screen);
2198 int max_col = maxRectCol(screen) + err;
2199
2200 if (xw->flags & ORIGIN)
2201 col += screen->lft_marg;
2202
2203 if (col < min_col)
2204 col = min_col;
2205 else if (col > max_col)
2206 col = max_col;
2207
2208 return col;
2209 }
2210
2211 #define LimitedParse(num, func, dft, err) \
2212 func(xw, (nparams > num && params[num] > 0) ? params[num] : dft, err)
2213
2214 /*
2215 * Copy the rectangle boundaries into a struct, providing default values as
2216 * needed.
2217 */
2218 void
xtermParseRect(XtermWidget xw,int nparams,int * params,XTermRect * target)2219 xtermParseRect(XtermWidget xw, int nparams, int *params, XTermRect *target)
2220 {
2221 TScreen *screen = TScreenOf(xw);
2222
2223 memset(target, 0, sizeof(*target));
2224 target->top = LimitedParse(0, limitedParseRow, minRectRow(screen), 1);
2225 target->left = LimitedParse(1, limitedParseCol, minRectCol(screen), 1);
2226 target->bottom = LimitedParse(2, limitedParseRow, maxRectRow(screen), 0);
2227 target->right = LimitedParse(3, limitedParseCol, maxRectCol(screen), 0);
2228 TRACE(("parsed %d params for rectangle %d,%d %d,%d default %d,%d %d,%d\n",
2229 nparams,
2230 target->top,
2231 target->left,
2232 target->bottom,
2233 target->right,
2234 minRectRow(screen),
2235 minRectCol(screen),
2236 maxRectRow(screen),
2237 maxRectCol(screen)));
2238 }
2239
2240 static Bool
validRect(XtermWidget xw,XTermRect * target)2241 validRect(XtermWidget xw, XTermRect *target)
2242 {
2243 TScreen *screen = TScreenOf(xw);
2244 Bool result = (target != 0
2245 && target->top >= minRectRow(screen)
2246 && target->left >= minRectCol(screen)
2247 && target->top <= target->bottom
2248 && target->left <= target->right
2249 && target->top <= maxRectRow(screen)
2250 && target->right <= maxRectCol(screen));
2251
2252 TRACE(("comparing against screensize %dx%d, is%s valid\n",
2253 maxRectRow(screen),
2254 maxRectCol(screen),
2255 result ? "" : " NOT"));
2256 return result;
2257 }
2258
2259 /*
2260 * Fills a rectangle with the given 8-bit character and video-attributes.
2261 * Colors and double-size attribute are unmodified.
2262 */
2263 void
ScrnFillRectangle(XtermWidget xw,XTermRect * target,int value,unsigned flags,Bool keepColors)2264 ScrnFillRectangle(XtermWidget xw,
2265 XTermRect *target,
2266 int value,
2267 unsigned flags,
2268 Bool keepColors)
2269 {
2270 IChar actual = (IChar) value;
2271 TScreen *screen = TScreenOf(xw);
2272
2273 TRACE(("filling rectangle with '%s' flags %#x\n",
2274 visibleIChars(&actual, 1), flags));
2275 if (validRect(xw, target)) {
2276 LineData *ld;
2277 int top = (target->top - 1);
2278 int left = (target->left - 1);
2279 int right = (target->right - 1);
2280 int bottom = (target->bottom - 1);
2281 int numcols = (right - left) + 1;
2282 int numrows = (bottom - top) + 1;
2283 unsigned attrs = flags;
2284 int row, col;
2285 int b_left = 0;
2286 int b_right = 0;
2287
2288 (void) numcols;
2289
2290 attrs &= ATTRIBUTES;
2291 attrs |= CHARDRAWN;
2292 for (row = bottom; row >= top; row--) {
2293 ld = getLineData(screen, row);
2294
2295 TRACE(("filling %d [%d..%d]\n", row, left, left + numcols));
2296
2297 if_OPT_WIDE_CHARS(screen, {
2298 if (left > 0) {
2299 if (ld->charData[left] == HIDDEN_CHAR) {
2300 b_left = 1;
2301 Clear1Cell(ld, left - 1);
2302 Clear1Cell(ld, left);
2303 }
2304 }
2305 if (right + 1 < (int) ld->lineSize) {
2306 if (ld->charData[right + 1] == HIDDEN_CHAR) {
2307 b_right = 1;
2308 Clear1Cell(ld, right);
2309 Clear1Cell(ld, right + 1);
2310 }
2311 }
2312 });
2313
2314 /*
2315 * Fill attributes, preserving colors.
2316 */
2317 for (col = left; col <= right; ++col) {
2318 unsigned temp = ld->attribs[col];
2319
2320 if (!keepColors) {
2321 UIntClr(temp, (FG_COLOR | BG_COLOR));
2322 }
2323 temp = attrs | (temp & (FG_COLOR | BG_COLOR)) | CHARDRAWN;
2324 ld->attribs[col] = (IAttr) temp;
2325 if_OPT_ISO_COLORS(screen, {
2326 if (attrs & (FG_COLOR | BG_COLOR)) {
2327 ld->color[col] = xtermColorPair(xw);
2328 }
2329 });
2330 }
2331
2332 for (col = left; col <= right; ++col)
2333 ld->charData[col] = actual;
2334
2335 if_OPT_WIDE_CHARS(screen, {
2336 size_t off;
2337 for_each_combData(off, ld) {
2338 memset(ld->combData[off] + left,
2339 0,
2340 (size_t) numcols * sizeof(CharData));
2341 }
2342 })
2343 }
2344 chararea_clear_displayed_graphics(screen,
2345 left,
2346 top,
2347 numcols, numrows);
2348 ScrnUpdate(xw,
2349 top,
2350 left - b_left,
2351 numrows,
2352 numcols + b_left + b_right,
2353 False);
2354 }
2355 }
2356
2357 #if OPT_DEC_RECTOPS
2358 /*
2359 * Copies the source rectangle to the target location, including video
2360 * attributes.
2361 *
2362 * This implementation ignores page numbers.
2363 *
2364 * The reference manual does not indicate if it handles overlapping copy
2365 * properly - so we make a local copy of the source rectangle first, then apply
2366 * the target from that.
2367 */
2368 void
ScrnCopyRectangle(XtermWidget xw,XTermRect * source,int nparam,int * params)2369 ScrnCopyRectangle(XtermWidget xw, XTermRect *source, int nparam, int *params)
2370 {
2371 TScreen *screen = TScreenOf(xw);
2372
2373 TRACE(("copying rectangle\n"));
2374
2375 if (nparam > 4)
2376 nparam = 4;
2377
2378 if (validRect(xw, source)) {
2379 XTermRect target;
2380 xtermParseRect(xw,
2381 ((nparam > 2) ? 2 : nparam),
2382 params,
2383 &target);
2384 if (validRect(xw, &target)) {
2385 Cardinal high = (Cardinal) (source->bottom - source->top) + 1;
2386 Cardinal wide = (Cardinal) (source->right - source->left) + 1;
2387 Cardinal size = (high * wide);
2388 int row, col;
2389 Cardinal j, k;
2390 LineData *ld;
2391 int b_left = 0;
2392 int b_right = 0;
2393
2394 CellData *cells = newCellData(xw, size);
2395
2396 if (cells != 0) {
2397
2398 TRACE(("OK - make copy %dx%d\n", high, wide));
2399 target.bottom = target.top + (int) (high - 1);
2400 target.right = target.left + (int) (wide - 1);
2401
2402 for (row = source->top - 1; row < source->bottom; ++row) {
2403 ld = getLineData(screen, row);
2404 if (ld == 0)
2405 continue;
2406 j = (Cardinal) (row - (source->top - 1));
2407 TRACE2(("ROW %d\n", row + 1));
2408 for (col = source->left - 1; col < source->right; ++col) {
2409 k = (Cardinal) (col - (source->left - 1));
2410 saveCellData(screen, cells,
2411 (j * wide) + k,
2412 ld, source, col);
2413 }
2414 }
2415 for (row = target.top - 1; row < target.bottom; ++row) {
2416 ld = getLineData(screen, row);
2417 if (ld == 0)
2418 continue;
2419 j = (Cardinal) (row - (target.top - 1));
2420 TRACE2(("ROW %d\n", row + 1));
2421 for (col = target.left - 1; col < target.right; ++col) {
2422 k = (Cardinal) (col - (target.left - 1));
2423 if (row >= getMinRow(screen)
2424 && row <= getMaxRow(screen)
2425 && col >= getMinCol(screen)
2426 && col <= getMaxCol(screen)
2427 && (j < high)
2428 && (k < wide)) {
2429 if_OPT_WIDE_CHARS(screen, {
2430 if (ld->charData[col] == HIDDEN_CHAR
2431 && (col + 1) == target.left) {
2432 b_left = 1;
2433 Clear1Cell(ld, col - 1);
2434 }
2435 if ((col + 1) == target.right
2436 && ld->charData[col] == HIDDEN_CHAR) {
2437 b_right = 1;
2438 }
2439 });
2440 restoreCellData(screen, cells,
2441 (j * wide) + k,
2442 ld, &target, col);
2443 }
2444 ld->attribs[col] |= CHARDRAWN;
2445 }
2446 #if OPT_BLINK_TEXT
2447 if (LineHasBlinking(screen, ld)) {
2448 LineSetBlinked(ld);
2449 } else {
2450 LineClrBlinked(ld);
2451 }
2452 #endif
2453 }
2454 free(cells);
2455
2456 ScrnUpdate(xw,
2457 (target.top - 1),
2458 (target.left - (1 + b_left)),
2459 (target.bottom - target.top) + 1,
2460 ((target.right - target.left) + (1 + b_left + b_right)),
2461 False);
2462 }
2463 }
2464 }
2465 }
2466
2467 /*
2468 * Modifies the video-attributes only - so selection (not a video attribute) is
2469 * unaffected. Colors and double-size flags are unaffected as well.
2470 *
2471 * FIXME: our representation for "invisible" does not work with this operation,
2472 * since the attribute byte is fully-allocated for other flags. The logic
2473 * is shown for INVISIBLE because it's harmless, and useful in case the
2474 * CHARDRAWN or PROTECTED flags are reassigned.
2475 */
2476 void
ScrnMarkRectangle(XtermWidget xw,XTermRect * target,Bool reverse,int nparam,int * params)2477 ScrnMarkRectangle(XtermWidget xw,
2478 XTermRect *target,
2479 Bool reverse,
2480 int nparam,
2481 int *params)
2482 {
2483 TScreen *screen = TScreenOf(xw);
2484 Bool exact = (screen->cur_decsace == 2);
2485
2486 TRACE(("%s %s\n",
2487 reverse ? "reversing" : "marking",
2488 (exact
2489 ? "rectangle"
2490 : "region")));
2491
2492 if (validRect(xw, target)) {
2493 LineData *ld;
2494 int top = target->top - 1;
2495 int bottom = target->bottom - 1;
2496 int row, col;
2497 int n;
2498
2499 for (row = top; row <= bottom; ++row) {
2500 int left = ((exact || (row == top))
2501 ? (target->left - 1)
2502 : getMinCol(screen));
2503 int right = ((exact || (row == bottom))
2504 ? (target->right - 1)
2505 : getMaxCol(screen));
2506
2507 ld = getLineData(screen, row);
2508
2509 TRACE(("marking %d [%d..%d]\n", row, left, right));
2510 for (col = left; col <= right; ++col) {
2511 unsigned flags = ld->attribs[col];
2512
2513 for (n = 0; n < nparam; ++n) {
2514 #if OPT_TRACE
2515 if (row == top && col == left)
2516 TRACE(("attr param[%d] %d\n", n + 1, params[n]));
2517 #endif
2518 if (reverse) {
2519 switch (params[n]) {
2520 case 1:
2521 flags ^= BOLD;
2522 break;
2523 case 4:
2524 flags ^= UNDERLINE;
2525 break;
2526 case 5:
2527 flags ^= BLINK;
2528 break;
2529 case 7:
2530 flags ^= INVERSE;
2531 break;
2532 case 8:
2533 flags ^= INVISIBLE;
2534 break;
2535 }
2536 } else {
2537 switch (params[n]) {
2538 case 0:
2539 UIntClr(flags, SGR_MASK);
2540 break;
2541 case 1:
2542 flags |= BOLD;
2543 break;
2544 case 4:
2545 flags |= UNDERLINE;
2546 break;
2547 case 5:
2548 flags |= BLINK;
2549 break;
2550 case 7:
2551 flags |= INVERSE;
2552 break;
2553 case 8:
2554 flags |= INVISIBLE;
2555 break;
2556 case 22:
2557 UIntClr(flags, BOLD);
2558 break;
2559 case 24:
2560 UIntClr(flags, UNDERLINE);
2561 break;
2562 case 25:
2563 UIntClr(flags, BLINK);
2564 break;
2565 case 27:
2566 UIntClr(flags, INVERSE);
2567 break;
2568 case 28:
2569 UIntClr(flags, INVISIBLE);
2570 break;
2571 }
2572 }
2573 }
2574 #if OPT_TRACE
2575 if (row == top && col == left)
2576 TRACE(("first mask-change is %#x\n",
2577 ld->attribs[col] ^ flags));
2578 #endif
2579 ld->attribs[col] = (IAttr) flags;
2580 }
2581 }
2582 ScrnRefresh(xw,
2583 (target->top - 1),
2584 (exact ? (target->left - 1) : getMinCol(screen)),
2585 (target->bottom - target->top) + 1,
2586 (exact
2587 ? ((target->right - target->left) + 1)
2588 : (getMaxCol(screen) - getMinCol(screen) + 1)),
2589 True);
2590 }
2591 }
2592
2593 /*
2594 * Resets characters to space, except where prohibited by DECSCA. Video
2595 * attributes (including color) are untouched.
2596 */
2597 void
ScrnWipeRectangle(XtermWidget xw,XTermRect * target)2598 ScrnWipeRectangle(XtermWidget xw,
2599 XTermRect *target)
2600 {
2601 TScreen *screen = TScreenOf(xw);
2602
2603 TRACE(("wiping rectangle\n"));
2604
2605 #define IsProtected(ld, col) \
2606 ((screen->protected_mode == DEC_PROTECT) \
2607 && (ld->attribs[col] & PROTECTED))
2608
2609 if (validRect(xw, target)) {
2610 LineData *ld;
2611 int top = target->top - 1;
2612 int left = target->left - 1;
2613 int right = target->right - 1;
2614 int bottom = target->bottom - 1;
2615 int numcols = (right - left) + 1;
2616 int numrows = (bottom - top) + 1;
2617 int row, col;
2618 int b_left = 0;
2619 int b_right = 0;
2620
2621 for (row = top; row <= bottom; ++row) {
2622 TRACE(("wiping %d [%d..%d]\n", row, left, right));
2623
2624 ld = getLineData(screen, row);
2625
2626 if_OPT_WIDE_CHARS(screen, {
2627 if (left > 0 && !IsProtected(ld, left)) {
2628 if (ld->charData[left] == HIDDEN_CHAR) {
2629 b_left = 1;
2630 Clear1Cell(ld, left - 1);
2631 Clear1Cell(ld, left);
2632 }
2633 }
2634 if (right + 1 < (int) ld->lineSize && !IsProtected(ld, right)) {
2635 if (ld->charData[right + 1] == HIDDEN_CHAR) {
2636 b_right = 1;
2637 Clear1Cell(ld, right);
2638 Clear1Cell(ld, right + 1);
2639 }
2640 }
2641 });
2642
2643 for (col = left; col <= right; ++col) {
2644 if (!IsProtected(ld, col)) {
2645 ld->attribs[col] |= CHARDRAWN;
2646 Clear1Cell(ld, col);
2647 }
2648 }
2649 }
2650 chararea_clear_displayed_graphics(screen,
2651 left,
2652 top,
2653 numcols, numrows);
2654 ScrnUpdate(xw,
2655 top,
2656 left - b_left,
2657 numrows,
2658 numcols + b_left + b_right,
2659 False);
2660 }
2661 }
2662
2663 /*
2664 * Compute a checksum, ignoring the page number (since we have only one page).
2665 */
2666 void
xtermCheckRect(XtermWidget xw,int nparam,int * params,int * result)2667 xtermCheckRect(XtermWidget xw,
2668 int nparam,
2669 int *params,
2670 int *result)
2671 {
2672 TScreen *screen = TScreenOf(xw);
2673 XTermRect target;
2674 LineData *ld;
2675 int total = 0;
2676 int trimmed = 0;
2677 int mode = screen->checksum_ext;
2678
2679 TRACE(("xtermCheckRect: %s%s%s%s%s%s%s\n",
2680 (mode == csDEC) ? "DEC" : "checksumExtension",
2681 (mode & csPOSITIVE) ? " !negative" : "",
2682 (mode & csATTRIBS) ? " !attribs" : "",
2683 (mode & csNOTRIM) ? " !trimmed" : "",
2684 (mode & csDRAWN) ? " !drawn" : "",
2685 (mode & csBYTE) ? " !byte" : "",
2686 (mode & cs8TH) ? " !7bit" : ""));
2687
2688 if (nparam > 2) {
2689 nparam -= 2;
2690 params += 2;
2691 }
2692 xtermParseRect(xw, nparam, params, &target);
2693 if (validRect(xw, &target)) {
2694 int top = target.top - 1;
2695 int bottom = target.bottom - 1;
2696 int row, col;
2697 Boolean first = True;
2698 int embedded = 0;
2699 DECNRCM_codes my_GR = screen->gsets[(int) screen->curgr];
2700
2701 for (row = top; row <= bottom; ++row) {
2702 int left = (target.left - 1);
2703 int right = (target.right - 1);
2704
2705 ld = getLineData(screen, row);
2706 if (ld == 0)
2707 continue;
2708 for (col = left; col <= right && col < (int) ld->lineSize; ++col) {
2709 int ch = ((ld->attribs[col] & CHARDRAWN)
2710 ? (int) ld->charData[col]
2711 : ' ');
2712 if (!(mode & csBYTE)) {
2713 unsigned c2 = (unsigned) ch;
2714 if (c2 > 0x7f && my_GR != nrc_ASCII) {
2715 c2 = xtermCharSetIn(xw, c2, my_GR);
2716 if (!(mode & cs8TH) && (c2 < 0x80))
2717 c2 |= 0x80;
2718 }
2719 ch = (c2 & 0xff);
2720 }
2721 if (!(mode & csATTRIBS)) {
2722 if (ld->attribs[col] & UNDERLINE)
2723 ch += 0x10;
2724 if (ld->attribs[col] & INVERSE)
2725 ch += 0x20;
2726 if (ld->attribs[col] & BLINK)
2727 ch += 0x40;
2728 if (ld->attribs[col] & BOLD)
2729 ch += 0x80;
2730 }
2731 if (first || (ch != ' ') || (ld->attribs[col] & DRAWX_MASK)) {
2732 trimmed += ch + embedded;
2733 embedded = 0;
2734 } else if (ch == ' ') {
2735 if ((mode & csNOTRIM))
2736 embedded += ch;
2737 }
2738 if ((ld->attribs[col] & CHARDRAWN)) {
2739 total += ch;
2740 if_OPT_WIDE_CHARS(screen, {
2741 /* FIXME - not counted if trimming blanks */
2742 if (!(mode & csBYTE)) {
2743 size_t off;
2744 for_each_combData(off, ld) {
2745 total += (int) ld->combData[off][col];
2746 }
2747 }
2748 })
2749 } else if (!(mode & csDRAWN)) {
2750 total += ch;
2751 }
2752 first = ((mode & csNOTRIM) != 0) ? True : False;
2753 }
2754 if (!(mode & csNOTRIM)) {
2755 embedded = 0;
2756 first = False;
2757 }
2758 }
2759 }
2760 if (!(mode & csNOTRIM))
2761 total = trimmed;
2762 if (!(mode & csPOSITIVE))
2763 total = -total;
2764 *result = total;
2765 }
2766 #endif /* OPT_DEC_RECTOPS */
2767
2768 #if OPT_MAXIMIZE
2769
2770 static _Xconst char *
ewmhProperty(int mode)2771 ewmhProperty(int mode)
2772 {
2773 _Xconst char *result;
2774 switch (mode) {
2775 default:
2776 result = 0;
2777 break;
2778 case 1:
2779 result = "_NET_WM_STATE_FULLSCREEN";
2780 break;
2781 case 2:
2782 result = "_NET_WM_STATE_MAXIMIZED_VERT";
2783 break;
2784 case 3:
2785 result = "_NET_WM_STATE_MAXIMIZED_HORZ";
2786 break;
2787 }
2788 return result;
2789 }
2790
2791 static void
set_resize_increments(XtermWidget xw)2792 set_resize_increments(XtermWidget xw)
2793 {
2794 TScreen *screen = TScreenOf(xw);
2795 int min_width = (2 * screen->border) + screen->fullVwin.sb_info.width;
2796 int min_height = (2 * screen->border);
2797 XSizeHints sizehints;
2798
2799 TRACE(("set_resize_increments\n"));
2800 memset(&sizehints, 0, sizeof(XSizeHints));
2801 sizehints.width_inc = FontWidth(screen);
2802 sizehints.height_inc = FontHeight(screen);
2803 sizehints.flags = PResizeInc;
2804 TRACE_HINTS(&sizehints);
2805 XSetWMNormalHints(screen->display, VShellWindow(xw), &sizehints);
2806
2807 TRACE(("setting values for widget %p:\n", (void *) SHELL_OF(xw)));
2808 TRACE((" base width %d\n", min_width));
2809 TRACE((" base height %d\n", min_width));
2810 TRACE((" min width %d\n", min_width + FontWidth(screen)));
2811 TRACE((" min height %d\n", min_width + FontHeight(screen)));
2812 TRACE((" width inc %d\n", FontWidth(screen)));
2813 TRACE((" height inc %d\n", FontHeight(screen)));
2814
2815 XtVaSetValues(SHELL_OF(xw),
2816 XtNbaseWidth, min_width,
2817 XtNbaseHeight, min_height,
2818 XtNminWidth, min_width + FontWidth(screen),
2819 XtNminHeight, min_height + FontHeight(screen),
2820 XtNwidthInc, FontWidth(screen),
2821 XtNheightInc, FontHeight(screen),
2822 (XtPointer) 0);
2823
2824 XFlush(XtDisplay(xw));
2825 }
2826
2827 static void
unset_resize_increments(XtermWidget xw)2828 unset_resize_increments(XtermWidget xw)
2829 {
2830 TScreen *screen = TScreenOf(xw);
2831 XSizeHints sizehints;
2832
2833 TRACE(("unset_resize_increments\n"));
2834 memset(&sizehints, 0, sizeof(XSizeHints));
2835 sizehints.width_inc = 1;
2836 sizehints.height_inc = 1;
2837 sizehints.flags = PResizeInc;
2838 TRACE_HINTS(&sizehints);
2839 XSetWMNormalHints(screen->display, VShellWindow(xw), &sizehints);
2840
2841 XtVaSetValues(SHELL_OF(xw),
2842 XtNwidthInc, 1,
2843 XtNheightInc, 1,
2844 (XtPointer) 0);
2845
2846 XFlush(XtDisplay(xw));
2847 }
2848
2849 static void
set_ewmh_hint(Display * dpy,Window window,int operation,_Xconst char * prop)2850 set_ewmh_hint(Display *dpy, Window window, int operation, _Xconst char *prop)
2851 {
2852 XEvent e;
2853 Atom atom_fullscreen = XInternAtom(dpy, prop, False);
2854 Atom atom_state = XInternAtom(dpy, "_NET_WM_STATE", False);
2855
2856 #if OPT_TRACE
2857 const char *what = "?";
2858 switch (operation) {
2859 case _NET_WM_STATE_ADD:
2860 what = "adding";
2861 break;
2862 case _NET_WM_STATE_REMOVE:
2863 what = "removing";
2864 break;
2865 }
2866 TRACE(("set_ewmh_hint %s %s\n", what, prop));
2867 #endif
2868
2869 memset(&e, 0, sizeof(e));
2870 e.xclient.type = ClientMessage;
2871 e.xclient.message_type = atom_state;
2872 e.xclient.display = dpy;
2873 e.xclient.window = window;
2874 e.xclient.format = 32;
2875 e.xclient.data.l[0] = operation;
2876 e.xclient.data.l[1] = (long) atom_fullscreen;
2877
2878 XSendEvent(dpy, DefaultRootWindow(dpy), False,
2879 SubstructureRedirectMask, &e);
2880 }
2881
2882 /*
2883 * Check if the given property is supported on the root window.
2884 *
2885 * The XGetWindowProperty function returns a list of Atom's which corresponds
2886 * to the output of xprop. The actual list (ignore the manpage, which refers
2887 * to an array of 32-bit values) is constructed by _XRead32, which uses long
2888 * as a datatype.
2889 *
2890 * Alternatively, we could check _NET_WM_ALLOWED_ACTIONS on the application's
2891 * window.
2892 */
2893 static Boolean
probe_netwm(Display * dpy,_Xconst char * propname)2894 probe_netwm(Display *dpy, _Xconst char *propname)
2895 {
2896 Atom atom_fullscreen = XInternAtom(dpy, propname, False);
2897 Atom atom_supported = XInternAtom(dpy, "_NET_SUPPORTED", False);
2898 Atom actual_type;
2899 int actual_format;
2900 long long_offset = 0;
2901 long long_length = 128; /* number of items to ask for at a time */
2902 unsigned int i;
2903 unsigned long nitems, bytes_after;
2904 unsigned char *args;
2905 long *ldata;
2906 Boolean has_capability = False;
2907 Boolean rc;
2908
2909 while (!has_capability) {
2910 rc = xtermGetWinProp(dpy,
2911 DefaultRootWindow(dpy),
2912 atom_supported,
2913 long_offset,
2914 long_length,
2915 AnyPropertyType, /* req_type */
2916 &actual_type, /* actual_type_return */
2917 &actual_format, /* actual_format_return */
2918 &nitems, /* nitems_return */
2919 &bytes_after, /* bytes_after_return */
2920 &args /* prop_return */
2921 );
2922 if (!rc
2923 || actual_type != XA_ATOM) {
2924 break;
2925 }
2926 ldata = (long *) (void *) args;
2927 for (i = 0; i < nitems; i++) {
2928 #if OPT_TRACE > 1
2929 char *name;
2930 if ((name = XGetAtomName(dpy, ldata[i])) != 0) {
2931 TRACE(("atom[%d] = %s\n", i, name));
2932 XFree(name);
2933 } else {
2934 TRACE(("atom[%d] = ?\n", i));
2935 }
2936 #endif
2937 if ((Atom) ldata[i] == atom_fullscreen) {
2938 has_capability = True;
2939 break;
2940 }
2941 }
2942 XFree(ldata);
2943
2944 if (!has_capability) {
2945 if (bytes_after != 0) {
2946 long remaining = (long) (bytes_after / sizeof(long));
2947 if (long_length > remaining)
2948 long_length = remaining;
2949 long_offset += (long) nitems;
2950 } else {
2951 break;
2952 }
2953 }
2954 }
2955
2956 TRACE(("probe_netwm(%s) ->%d\n", propname, has_capability));
2957 return has_capability;
2958 }
2959
2960 /*
2961 * Alter fullscreen mode for the xterm widget, if the window manager supports
2962 * that feature.
2963 */
2964 void
FullScreen(XtermWidget xw,int new_ewmh_mode)2965 FullScreen(XtermWidget xw, int new_ewmh_mode)
2966 {
2967 TScreen *screen = TScreenOf(xw);
2968 Display *dpy = screen->display;
2969 int old_ewmh_mode;
2970 _Xconst char *oldprop;
2971 _Xconst char *newprop;
2972
2973 int which = 0;
2974 Window window;
2975
2976 #if OPT_TEK4014
2977 if (TEK4014_ACTIVE(xw)) {
2978 which = 1;
2979 window = TShellWindow;
2980 } else
2981 #endif
2982 window = VShellWindow(xw);
2983
2984 old_ewmh_mode = xw->work.ewmh[which].mode;
2985 oldprop = ewmhProperty(old_ewmh_mode);
2986 newprop = ewmhProperty(new_ewmh_mode);
2987
2988 TRACE(("FullScreen %d:%s -> %d:%s\n",
2989 old_ewmh_mode, NonNull(oldprop),
2990 new_ewmh_mode, NonNull(newprop)));
2991
2992 if (new_ewmh_mode == old_ewmh_mode) {
2993 TRACE(("...unchanged\n"));
2994 return;
2995 } else if (new_ewmh_mode < 0 || new_ewmh_mode > MAX_EWMH_MODE) {
2996 TRACE(("BUG: FullScreen %d\n", new_ewmh_mode));
2997 return;
2998 } else if (new_ewmh_mode == 0) {
2999 xw->work.ewmh[which].checked[new_ewmh_mode] = True;
3000 xw->work.ewmh[which].allowed[new_ewmh_mode] = True;
3001 } else if (resource.fullscreen == esNever) {
3002 xw->work.ewmh[which].checked[new_ewmh_mode] = True;
3003 xw->work.ewmh[which].allowed[new_ewmh_mode] = False;
3004 } else if (!xw->work.ewmh[which].checked[new_ewmh_mode]) {
3005 xw->work.ewmh[which].checked[new_ewmh_mode] = True;
3006 xw->work.ewmh[which].allowed[new_ewmh_mode] = probe_netwm(dpy, newprop);
3007 }
3008
3009 if (xw->work.ewmh[which].allowed[new_ewmh_mode]) {
3010 TRACE(("...new EWMH mode is allowed\n"));
3011 if (new_ewmh_mode && !xw->work.ewmh[which].mode) {
3012 unset_resize_increments(xw);
3013 set_ewmh_hint(dpy, window, _NET_WM_STATE_ADD, newprop);
3014 } else if (xw->work.ewmh[which].mode && !new_ewmh_mode) {
3015 if (!xw->misc.resizeByPixel) {
3016 set_resize_increments(xw);
3017 }
3018 set_ewmh_hint(dpy, window, _NET_WM_STATE_REMOVE, oldprop);
3019 } else {
3020 set_ewmh_hint(dpy, window, _NET_WM_STATE_REMOVE, oldprop);
3021 set_ewmh_hint(dpy, window, _NET_WM_STATE_ADD, newprop);
3022 }
3023 xw->work.ewmh[which].mode = new_ewmh_mode;
3024 update_fullscreen();
3025 } else {
3026 Bell(xw, XkbBI_MinorError, 100);
3027 }
3028 }
3029 #endif /* OPT_MAXIMIZE */
3030