1 /*--------------------------------*-C-*--------------------------------------*
2  * File:      screen.c
3  *---------------------------------------------------------------------------*
4  * Copyright (C) 2001 (cursor color) Jordan DeLong <fracture at allusion dot net>
5  * Copyright (C) 2000 Sasha Vasko <sashav at sprintmail dot com>
6  * Copyright (C) 1997,1998 Geoff Wing <gcw at pobox dot com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *--------------------------------------------------------------------------*/
22 /*--------------------------------------------------------------------------*
23  * Originally written:
24  *    1997,1998 Geoff Wing <mason@primenet.com.au>
25  *              - The routine names and calling structure was based upon
26  *                previous work by Robert Nation.  Most things have gone
27  *                through major change.
28  *
29  *    Michael Bruun Petersen" <mbp@image.dk>
30  *		- tinting fix
31  *    2002      Alexis <materm@tele2.fr>
32  *              - modifications for multi-terms support
33  *--------------------------------------------------------------------------*/
34 /*
35  * We handle _all_ screen updates and selections
36  *
37  * $Id: screen.c,v 1.16 2004/08/15 16:10:27 alexis Exp $
38  */
39 
40 #include "../config.h"
41 
42 #ifdef DEBUG
43 #define DEBUG_SCR_ALEXIS 0
44 #define DEBUG_SEL_ALEXIS 0
45 #else
46 #define DEBUG_SCR_ALEXIS 0
47 #define DEBUG_SEL_ALEXIS 0
48 #endif
49 
50 #if DEBUG_SCR_ALEXIS
51 #define DSCR_ALEXIS(d,x) if(d <= DEBUG_SCR_ALEXIS) fprintf x
52 #else
53 #define DSCR_ALEXIS(d,x)
54 #endif
55 
56 #if DEBUG_SEL_ALEXIS
57 #define DSEL_ALEXIS(d,x) if(d <= DEBUG_SEL_ALEXIS) fprintf x
58 #else
59 #define DSEL_ALEXIS(d,x)
60 #endif
61 
62 
63 
64 #define INTERN_SCREEN
65 #define LIBAFTERSTEP_HEADER_INCLUDED
66 
67 #include "rxvt.h"		/* NECESSARY */
68 
69 #include <X11/Xatom.h>
70 #include <X11/Xmd.h>		/* get the typedef for CARD32 */
71 
72 static screen_t screen[MAX_PAGES];
73 
74 int             colors_changed = 0;	/* to indicate that foreground and background colors has changed */
75 
76 /* ------------------------------------------------------------------------- */
77 #ifdef MULTICHAR_SET
78 short           multi_byte;	/* set ==> currently using 2 bytes per glyph */
79 short           lost_multi;	/* set ==> we only got half a glyph */
80 enum
81 {
82 	SBYTE, WBYTE
83 }
84 chstat;
85 
86 # define RESET_CHSTAT			\
87     if (chstat == WBYTE)		\
88 	chstat = SBYTE, lost_multi = 1
89 #else
90 # define RESET_CHSTAT
91 #endif
92 
93 typedef enum
94 {
95 	EUCJ, SJIS,		/* KANJI methods */
96 	BIG5, CNS		/* BIG5 methods: CNS not implemented */
97 }
98 ENC_METHOD;
99 
100 #if defined(KANJI) || defined(ZH)
101 ENC_METHOD      encoding_method;
102 #endif
103 
104 /* ------------------------------------------------------------------------- */
105 #define PROP_SIZE		4096
106 #define TABSIZE			8	/* default tab size */
107 
108 #define DEBUG_SCREEN 1
109 #ifdef DEBUG_SCREEN
110 # define D_SCREEN(x)		fprintf x ; fputc('\n', stderr)
111 #else
112 # define D_SCREEN(x)
113 #endif
114 #ifdef DEBUG_SELECT
115 # define D_SELECT(x)		fprintf x ; fputc('\n', stderr)
116 #else
117 # define D_SELECT(x)
118 #endif
119 
120 /* ------------------------------------------------------------------------- *
121  *             GENERAL SCREEN AND SELECTION UPDATE ROUTINES                  *
122  * ------------------------------------------------------------------------- */
123 
124 #define f_ZERO_SCROLLBACK(page)					\
125   if ((Options & Opt_scrollTtyOutputInh) == 0)	\
126     TermWin.vts[page].view_start = 0
127 
128 #define CHECK_SELECTION(pagepage,x)				\
129     if (selection.op)					\
130 	f_selection_check(page,x)
131 #define CLEAR_SELECTION					\
132     selection.beg.row = selection.beg.col		\
133 	= selection.end.row = selection.end.col = 0
134 #define CLEAR_ALL_SELECTION				\
135     selection.beg.row = selection.beg.col		\
136 	= selection.mark.row = selection.mark.col	\
137 	= selection.end.row = selection.end.col = 0
138 
139 #define ROW_AND_COL_IS_AFTER(A, B, C, D)				\
140     (((A) > (C)) || (((A) == (C)) && ((B) > (D))))
141 #define ROW_AND_COL_IS_BEFORE(A, B, C, D)				\
142     (((A) < (C)) || (((A) == (C)) && ((B) < (D))))
143 #define ROW_AND_COL_IN_ROW_AFTER(A, B, C, D)				\
144     (((A) == (C)) && ((B) > (D)))
145 #define ROW_AND_COL_IN_ROW_ON_OR_AFTER(A, B, C, D)			\
146     (((A) == (C)) && ((B) >= (D)))
147 #define ROW_AND_COL_IN_ROW_BEFORE(A, B, C, D)				\
148     (((A) == (C)) && ((B) < (D)))
149 #define ROW_AND_COL_IN_ROW_ON_OR_BEFORE(A, B, C, D)			\
150     (((A) == (C)) && ((B) <= (D)))
151 
152 /* these must be row_col_t */
153 #define ROWCOL_IS_AFTER(X, Y)						\
154     ROW_AND_COL_IS_AFTER((X).row, (X).col, (Y).row, (Y).col)
155 #define ROWCOL_IS_BEFORE(X, Y)						\
156     ROW_AND_COL_IS_BEFORE((X).row, (X).col, (Y).row, (Y).col)
157 #define ROWCOL_IN_ROW_AFTER(X, Y)					\
158     ROW_AND_COL_IN_ROW_AFTER((X).row, (X).col, (Y).row, (Y).col)
159 #define ROWCOL_IN_ROW_BEFORE(X, Y)					\
160     ROW_AND_COL_IN_ROW_BEFORE((X).row, (X).col, (Y).row, (Y).col)
161 #define ROWCOL_IN_ROW_ON_OR_AFTER(X, Y)					\
162     ROW_AND_COL_IN_ROW_ON_OR_AFTER((X).row, (X).col, (Y).row, (Y).col)
163 #define ROWCOL_IN_ROW_ON_OR_BEFORE(X, Y)				\
164     ROW_AND_COL_IN_ROW_ON_OR_BEFORE((X).row, (X).col, (Y).row, (Y).col)
165 
print_info_screen()166 void print_info_screen() {
167   fprintf(stderr,"screen[%d] : tscroll: %d, bscroll: %d, lscroll: %d, rscroll: %d\n",TermWin.active_page,
168     screen[TermWin.active_page].tscroll,screen[TermWin.active_page].bscroll,
169     screen[TermWin.active_page].lscroll,screen[TermWin.active_page].rscroll
170   );
171 }
172 
173 /*
174  * CLEAR_ROWS : clear <num> rows starting from row <row>
175  * CLEAR_CHARS: clear <num> chars starting from pixel position <x,y>
176  * ERASE_ROWS : set <num> rows starting from row <row> to the foreground colour
177  */
178 
179 # define drawBufferPage(x)	(TermWin.vts[x].vt)
180 void
f_CLEAR_ROWS(int page,unsigned row,unsigned num)181 f_CLEAR_ROWS(int page,unsigned row, unsigned num)
182 {
183 	unsigned        line_h = Height2Pixel(1) - 1;
184 	register unsigned hy = (line_h + 1) * num, y = Row2Pixel(row);
185 
186   DSCR_ALEXIS(2,(stderr,"vt[%d] is %smapped\n",page,TermWin.vts[page].bMapped ? "" : "Un"));
187 	if (!TermWin.vts[page].bMapped)
188 		return;
189 
190 	if (y < TermWin_internalBorder + line_h)
191 	{
192 		y = 0;
193 		hy += TermWin_internalBorder;
194 	}
195 	if (y + hy > (TermWin.height + TermWin_internalBorder) - line_h)
196 		hy = (TermWin.height - y) + TermWin_internalBorders;
197 
198 	XClearArea(Xdisplay, drawBufferPage(page), 0, y,
199 		   TermWin.width + TermWin_internalBorders, hy, 0);
200 #if defined(BACKGROUND_IMAGE) || defined(TRANSPARENT)
201 	if (TermWin.vts[page].tintGC)
202 	{
203 		XFillRectangle(Xdisplay, drawBufferPage(page), TermWin.vts[page].tintGC,
204       0, y, TermWin.width + TermWin_internalBorders,hy);
205 	}
206 #endif
207 }
208 
209 void
f_CLEAR_CHARS(int page,unsigned x,unsigned y,unsigned num)210 f_CLEAR_CHARS(int page,unsigned x, unsigned y, unsigned num)
211 {
212 	unsigned char_w = Width2Pixel(1) - 1;
213   unsigned line_h = Height2Pixel(1) - 1;
214 	register unsigned hx = (char_w + 1) * num, hy = line_h + 1;
215 
216 	if (!TermWin.vts[page].bMapped)
217 		return;
218 
219 	if (x < TermWin_internalBorder + char_w)
220 	{
221 		x = 0;
222 		hx += TermWin_internalBorder;
223 	}
224 	if (y < TermWin_internalBorder + line_h)
225 	{
226 		y = 0;
227 		hy += TermWin_internalBorder;
228 	}
229 
230 	if (x + hx > (TermWin.width + TermWin_internalBorder) - char_w)
231 		hx = (TermWin.width + TermWin_internalBorders + 1) - x;
232 	if (y + hy > (TermWin.height + TermWin_internalBorder) - line_h)
233 		hy = (TermWin.height + TermWin_internalBorders + 1) - y;
234 	XClearArea(Xdisplay, drawBufferPage(page), x, y, hx, hy, 0);
235 #if defined(BACKGROUND_IMAGE) || defined(TRANSPARENT)
236 	if (TermWin.vts[page].tintGC)
237 	{
238 		XFillRectangle(Xdisplay, drawBufferPage(page), TermWin.vts[page].tintGC, x, y, hx,hy);
239 	}
240 #endif
241 }
242 
243 
244 #define f_ERASE_ROWS(page,row, num) 						\
245     XFillRectangle(Xdisplay, drawBufferPage(page), TermWin.vts[page].gc,			\
246 		   Col2Pixel(0), Row2Pixel(row),			\
247 		   TermWin.width, Height2Pixel(num))
248 
249 /* ------------------------------------------------------------------------- *
250  *                        SCREEN `COMMON' ROUTINES                           *
251  * ------------------------------------------------------------------------- */
252 /* Fill part/all of a line with blanks. */
253 /* PROTO */
254 void
blank_line(text_t * et,rend_t * er,int width,rend_t efs)255 blank_line(text_t * et, rend_t * er, int width, rend_t efs)
256 {
257 	MEMSET(et, ' ', width);
258 	for (; width--;)
259 		*er++ = efs;
260 }
261 
262 /* ------------------------------------------------------------------------- */
263 /* allocate memory for this screen line and blank it appropriately */
264 /* PROTO */
265 void
f_make_screen_mem(int page,text_t ** tp,rend_t ** rp,int row,rend_t rstyle)266 f_make_screen_mem(int page,text_t ** tp, rend_t ** rp, int row, rend_t rstyle)
267 {
268 	tp[row] = MALLOC(sizeof(text_t) * TermWin.vts[page].bcol);
269 	rp[row] = MALLOC(sizeof(rend_t) * TermWin.vts[page].bcol);
270 	blank_line(tp[row], rp[row], TermWin.vts[page].bcol, rstyle);
271 }
272 
273 /* ------------------------------------------------------------------------- *
274  *                          SCREEN INITIALISATION                            *
275  * ------------------------------------------------------------------------- */
276 static int prev_nrows[MAX_PAGES];
277 static int prev_bcols[MAX_PAGES];
278 
scr_init()279 void scr_init() {
280   int i;
281 
282   for(i=0; i < MAX_PAGES; i++) {
283     prev_nrows[i] = -1;
284     prev_bcols[i] = -1;
285   }
286 }
287 
288 
289 #ifdef DEBUG_SCR_ALEXIS
290 
put_screen(int page)291 void put_screen(int page) {
292   int i,j;
293   fprintf(stderr,"tscroll:%d, nscroll:%d, nscrolled:%d\n",screen[page].tscroll,
294     screen[page].bscroll,TermWin.vts[page].nscrolled);
295   for(i=0; i < TermWin.vts[page].saveLines; i++) {
296     if(screen[page].text[i]) {
297       fprintf(stderr,"saveLines.text[%d] = ",i);
298       for(j=0; j < screen[page].tlen[i]; j++) {
299         fputc(screen[page].text[i][j],stderr);
300       }
301       fputc('\n',stderr);
302     } else {
303       fprintf(stderr,"saveLines.text[%d] = NULL\n",i);
304     }
305   }
306   for(; i < TermWin.vts[page].saveLines+TermWin.nrow; i++) {
307     if(screen[page].text[i]) {
308       fprintf(stderr,"screen.text[%d] = ",i);
309       for(j=0; j < screen[page].tlen[i]; j++) {
310         fputc(screen[page].text[i][j],stderr);
311       }
312       fputc('\n',stderr);
313     } else {
314       fprintf(stderr,"screen.text[%d] = NULL\n",i);
315     }
316   }
317 }
318 
put_drawn(int page)319 void put_drawn(int page) {
320   int i,j;
321   for(i=0; i < TermWin.nrow; i++) {
322     if(drawn_text[i]) {
323       fprintf(stderr,"drawn_text[%d] = ",i);
324       for(j=0; j < screen[page].tlen[i]; j++) {
325         fputc(drawn_text[i][j],stderr);
326       }
327       fputc('\n',stderr);
328     } else {
329       fprintf(stderr,"drawn_text[%d] = NULL",i);
330     }
331   }
332 }
333 
334 
335 #define display_screen(page) put_screen(page)
336 #define display_drawn(page) put_drawn(page)
337 #else
338 #define display_screen(page)
339 #define display_drawn(page)
340 #endif  /* DEBUG_SCR_ALEXIS */
341 
342 
f_scr_reset(int page)343 void f_scr_reset(int page)
344 {
345   int        i, j, k, total_rows, prev_total_rows;
346   rend_t     setrstyle;
347   static int prev_nrow = -1;
348   static int prev_ncol = -1;
349   static int scr_mem_done = 0;
350   static int resize_col_done = 0;
351 
352   DSCR_ALEXIS(1,(stderr, "scr_reset(%d)\n",page));
353 
354   TermWin.vts[page].view_start = 0;
355   RESET_CHSTAT;
356 
357   if (TermWin.vts[page].bcol == prev_bcols[page] && TermWin.nrow == prev_nrows[page]) {
358     DSCR_ALEXIS(1,(stderr,"scr_reset : no reset\n"));
359     return;
360   }
361 
362 #ifdef DEBUG_STRICT
363   assert(TermWin.vts[page].saveLines >= 0);
364 #else				/* drive with your eyes closed */
365   MAX_IT(TermWin.vts[page].saveLines, 0);
366 #endif
367 
368   total_rows = TermWin.nrow + TermWin.vts[page].saveLines;
369   prev_total_rows = prev_nrows[page] + TermWin.vts[page].saveLines;
370 
371   screen[page].tscroll = 0;
372   screen[page].bscroll = (TermWin.nrow - 1);
373 
374   /* *INDENT-OFF* */
375   if (prev_nrows[page] == -1) {
376 /*
377  * A: first time called so just malloc everything : don't rely on realloc
378  *    Note: this is still needed so that all the scrollback lines are NULL
379  */
380     DSCR_ALEXIS(2,(stderr, "scr_reset(): first call\n",page));
381     screen[page].text	= CALLOC(text_t * , total_rows);
382     screen[page].tlen	= CALLOC(R_int16_t, total_rows);
383     screen[page].rend = CALLOC(rend_t *, total_rows  );
384 
385     /* - on fait attention de n'allouer buf_*, swap_*, et
386      *   drawn_* qu'une seule fois si +sieurs appel de scr_reset
387      * - idem pour selection
388      */
389     if( prev_nrow == -1 ) {
390       DSCR_ALEXIS(2,(stderr, "scr_reset(): buf, drawn et swap initialised\n"));
391       buf_text	= CALLOC(text_t * , total_rows);
392       buf_tlen	= CALLOC(R_int16_t, total_rows);
393       buf_rend  = CALLOC(rend_t *, total_rows);
394 
395       drawn_text	= CALLOC(text_t * , TermWin.nrow);
396       drawn_rend  = CALLOC(rend_t *, TermWin.nrow);
397       for(i=0; i < TermWin.nrow; i++) {
398 
399         f_make_screen_mem(page,drawn_text, drawn_rend, i, DEFAULT_RSTYLE );
400       }
401 
402       swap.text	= CALLOC(text_t * , TermWin.nrow);
403       swap.tlen	= CALLOC(R_int16_t, TermWin.nrow);
404       swap.rend = CALLOC(rend_t *, TermWin.nrow);
405       for(i=0; i < TermWin.nrow; i++) {
406         f_make_screen_mem(page,swap.text, swap.rend, i, DEFAULT_RSTYLE);
407         swap.tlen[i] = 0;
408       }
409       swap.flags = Screen_DefaultFlags;
410 
411       selection.text = NULL;
412       selection.op = SELECTION_CLEAR;
413       selection.screen = PRIMARY;
414       selection.clicks = 0;
415       CLEAR_ALL_SELECTION;
416 
417       tabs = MALLOC(TermWin.vts[page].bcol * sizeof(char));
418       for(i=0; i < TermWin.vts[page].bcol; i++) {
419         tabs[i] = (i % TABSIZE == 0) ? 1 : 0;
420       }
421     }
422 
423     for (i = 0; i < TermWin.nrow; i++) {
424       j = i + TermWin.vts[page].saveLines;
425       f_make_screen_mem(page,screen[page].text, screen[page].rend, j, DEFAULT_RSTYLE);
426       screen[page].tlen[j] = 0;
427     }
428 
429     TermWin.vts[page].nscrolled = 0;	/* no saved lines */
430     screen[page].flags = Screen_DefaultFlags;
431     screen[page].cur.row = screen[page].cur.col = 0;
432     save[page].cur.row = save[page].cur.col = 0;
433     save[page].charset = 0;
434     save[page].charset_char = 'B';
435     rstyle = save[page].rstyle = DEFAULT_RSTYLE;
436     MEMSET(charsets, 'B', sizeof(charsets));
437     current_screen = PRIMARY;
438     rvideo = 0;
439 #ifdef MULTICHAR_SET
440     multi_byte = 0;
441     lost_multi = 0;
442     chstat = SBYTE;
443 # ifdef KANJI
444     encoding_method = EUCJ;
445 # else
446     encoding_method = BIG5;
447 # endif
448 #endif
449 
450   } else {
451 /*
452  * B1: add or delete rows as appropriate
453  */
454     setrstyle = DEFAULT_RSTYLE | (rvideo ? RS_RVid : 0);
455     DSCR_ALEXIS(2,(stderr, "scr_reset(): general case\n",page));
456 
457     if (TermWin.nrow < prev_nrows[page]) {
458     /* delete rows */
459       DSCR_ALEXIS(2,(stderr,"removing rows: %d->%d\n",
460         prev_nrows[page],TermWin.nrow));
461       k = min(TermWin.vts[page].nscrolled, prev_nrows[page] - TermWin.nrow);
462 
463       // il faut scroller vers le haut
464       // du nombre de ligne qu'on a perdu
465       f_scroll_text(page,0, prev_nrows[page] - 1, k, 1);
466 
467       for (i = TermWin.nrow; i < prev_nrows[page]; i++) {
468         j = i + TermWin.vts[page].saveLines;
469         if (screen[page].text[j])
470             FREE(screen[page].text[j]);
471 
472         if (screen[page].rend[j])
473             FREE(screen[page].rend[j]);
474       }
475 
476       if( prev_nrow != TermWin.nrow ) {
477         for(i = TermWin.nrow; i < prev_nrows[page]; i++) {
478           if (swap.text[i]) {
479             FREE(swap.text[i]);
480           }
481 
482           if (swap.rend[i]) {
483             FREE(swap.rend[i]);
484           }
485 
486           FREE(drawn_text[i]);
487           FREE(drawn_rend[i]);
488 
489         }
490       }
491     /* we have fewer rows so fix up number of scrolled lines */
492       MIN_IT(screen[page].cur.row, TermWin.nrow - 1);
493       MIN_IT(swap.cur.row, TermWin.nrow - 1);
494     }
495 
496     if(TermWin.nrow != prev_nrows[page]) {
497       screen[page].text = REALLOC(screen[page].text, total_rows  *sizeof(text_t*));
498       screen[page].tlen = REALLOC(screen[page].tlen, total_rows  *sizeof(R_int16_t));
499       if( prev_nrow != TermWin.nrow ) {
500         DSCR_ALEXIS(2,(stderr,"reallocating swap, buf et drawn\n"));
501         buf_text  	= REALLOC(buf_text   , total_rows  *sizeof(text_t*));
502         buf_tlen  	= REALLOC(buf_tlen   , total_rows  *sizeof(R_int16_t));
503         buf_rend  	= REALLOC(buf_rend   , total_rows  *sizeof(rend_t*));
504 
505         drawn_text  = REALLOC(drawn_text , TermWin.nrow*sizeof(text_t*));
506         drawn_rend  = REALLOC(drawn_rend , TermWin.nrow*sizeof(rend_t*));
507 
508 
509         swap.text  	= REALLOC(swap.text  , TermWin.nrow*sizeof(text_t*));
510         swap.tlen   = REALLOC(swap.tlen  , total_rows  *sizeof(R_int16_t));
511         swap.rend  	= REALLOC(swap.rend  , TermWin.nrow*sizeof(rend_t*));
512       }
513       screen[page].rend = REALLOC(screen[page].rend, total_rows  *sizeof(rend_t*));
514     }
515 
516     if (TermWin.nrow > prev_nrows[page]) {
517       /* add rows */
518       DSCR_ALEXIS(2,(stderr,"adding rows: %d->%d\n",
519         prev_nrows[page],TermWin.nrow));
520       /* k correspond au nbr de lignes qui vont passer de la partie
521        * nscrolled a la partie [tscroll,bscroll] => il faut allouer
522        * k nouvelles lgn
523        */
524       k = min(TermWin.vts[page].nscrolled, TermWin.nrow - prev_nrows[page]);
525 
526       /* on fait l'allocation des nouvelles lgn a la fin
527        */
528       for (i = prev_total_rows; i < total_rows - k; i++) {
529         f_make_screen_mem(page,screen[page].text, screen[page].rend, i, setrstyle);
530         screen[page].tlen[i] = 0;
531       }
532       for (i = total_rows - k; i < total_rows; i++) {
533         screen[page].text[i] = NULL;
534         screen[page].rend[i] = NULL;
535         screen[page].tlen[i] = 0;
536       }
537       /* on alloue les nouvelles lgn de la partie
538        * qui n'est pas scrollee seulement pour swap et drawn_*
539        */
540       if( prev_nrow != TermWin.nrow ) {
541 
542         for (i = prev_nrows[page]; i < TermWin.nrow; i++) {
543           f_make_screen_mem(page,swap.text, swap.rend, i, setrstyle);
544           f_make_screen_mem(page,drawn_text, drawn_rend, i, setrstyle );
545           swap.tlen[i] = 0;
546         }
547 
548       }
549 
550       if (k > 0) {
551         f_scroll_text(page,0, TermWin.nrow - 1, -k, 1);
552         screen[page].cur.row += k;
553         TermWin.vts[page].nscrolled -= k;
554         for (i = TermWin.vts[page].saveLines - TermWin.vts[page].nscrolled; k--; i--)
555           if (screen[page].text[i] == NULL) {
556             f_make_screen_mem(page,screen[page].text, screen[page].rend, i,setrstyle);
557             screen[page].tlen[i] = 0;
558           }
559       }
560 #ifdef DEBUG_STRICT
561       assert(screen[page].cur.row < TermWin.nrow);
562       assert(swap.cur.row < TermWin.nrow);
563 #else				/* drive with your eyes closed */
564       MIN_IT(screen[page].cur.row, TermWin.nrow - 1);
565       MIN_IT(swap.cur.row, TermWin.nrow - 1);
566 #endif
567     }
568 
569 /* B2: resize columns */
570     if (TermWin.vts[page].bcol != prev_bcols[page]) {
571       for (i = 0; i < total_rows; i++) {
572         if (screen[page].text[i]) {
573           screen[page].text[i] = REALLOC(screen[page].text[i],
574           TermWin.vts[page].bcol * sizeof(text_t));
575           screen[page].rend[i] = REALLOC(screen[page].rend[i],
576           TermWin.vts[page].bcol * sizeof(rend_t));
577           MIN_IT(screen[page].tlen[i], TermWin.vts[page].bcol);
578           if (TermWin.vts[page].bcol > prev_bcols[page])
579             blank_line(&(screen[page].text[i][prev_bcols[page]]),&(screen[page].rend[i][prev_bcols[page]]),
580               TermWin.vts[page].bcol - prev_bcols[page], setrstyle);
581         }
582       }
583 
584       /* resize swap and drawn only if we see that ncol has changed
585        * after the last call to scr_reset
586        */
587       if( prev_ncol !=  TermWin.vts[page].bcol ) {
588         DSCR_ALEXIS(2,(stderr,"resizing col\n"));
589         for (i = 0; i < TermWin.nrow; i++) {
590           drawn_text[i] = REALLOC(drawn_text[i],TermWin.vts[page].bcol * sizeof(text_t));
591           drawn_rend[i] = REALLOC(drawn_rend[i],TermWin.vts[page].bcol * sizeof(rend_t));
592           if (swap.text[i]) {
593             swap.text[i] = REALLOC(swap.text[i],TermWin.vts[page].bcol * sizeof(text_t));
594             swap.rend[i] = REALLOC(swap.rend[i],TermWin.vts[page].bcol * sizeof(rend_t));
595             MIN_IT(swap.tlen[i], TermWin.vts[page].bcol);
596             if (TermWin.vts[page].bcol > prev_bcols[page])
597               blank_line(&(swap.text[i][prev_bcols[page]]),&(swap.rend[i][prev_bcols[page]]),
598                 TermWin.vts[page].bcol - prev_bcols[page], setrstyle);
599           }
600           if (TermWin.vts[page].bcol > prev_bcols[page])
601             blank_line(&(drawn_text[i][prev_bcols[page]]),&(drawn_rend[i][prev_bcols[page]]),
602               TermWin.vts[page].bcol - prev_bcols[page], setrstyle);
603         }
604         if (tabs)
605           FREE(tabs);
606         tabs = MALLOC(TermWin.vts[page].bcol * sizeof(char));
607 
608         for (i = 0; i < TermWin.vts[page].bcol; i++)
609           tabs[i] = (i % TABSIZE == 0) ? 1 : 0;
610       }
611 
612       MIN_IT(screen[page].cur.col, TermWin.vts[page].bcol - 1);
613       MIN_IT(swap.cur.col, TermWin.vts[page].bcol - 1);
614     } //end of -> if (TermWin.vts[page].bcol != prev_bcols[page])
615   }
616 
617   prev_nrows[page] = TermWin.nrow;
618   prev_nrow = TermWin.nrow;
619 
620   prev_bcols[page] = TermWin.vts[page].bcol;
621   prev_ncol = TermWin.vts[page].bcol;
622 
623   /* don't do that here because the fd that page refer to is
624    * is created ...
625    * do it in f_run_command
626    */
627   /* f_tt_resize(page); */
628 
629 }
630 
631 /* ------------------------------------------------------------------------- */
632 /*
633  * Free everything.  That way malloc debugging can find leakage.
634  */
635 // on ne libere drawn que si c'est le dernier screen qui reste
636 /* PROTO */
637 void
f_scr_release(int page,int release_drawn)638 f_scr_release(int page,int release_drawn)
639 {
640 	int             i, total_rows;
641 
642   DSCR_ALEXIS(1,(stderr,"f_scr_release(%d,%d)\n",page,release_drawn));
643 	total_rows = TermWin.nrow + TermWin.vts[page].saveLines;
644 	for (i = 0; i < total_rows; i++)
645 	{
646 		if (screen[page].text[i])
647 		{		/* then so is screen.rend[i] */
648 			FREE(screen[page].text[i]);
649 			FREE(screen[page].rend[i]);
650 		}
651 	}
652   if(release_drawn) {
653     for (i = 0; i < TermWin.nrow; i++)
654     {
655       FREE(drawn_text[i]);
656       FREE(drawn_rend[i]);
657       FREE(swap.text[i]);
658       FREE(swap.rend[i]);
659     }
660 	}
661 	FREE(screen[page].text);
662 	FREE(screen[page].tlen);
663 	FREE(screen[page].rend);
664   if( release_drawn) {
665     FREE(drawn_text);
666     FREE(drawn_rend);
667     FREE(buf_text);
668     FREE(buf_tlen);
669     FREE(buf_rend);
670    	FREE(swap.text);
671     FREE(swap.tlen);
672     FREE(swap.rend);
673     FREE(tabs);
674   }
675 
676 
677 /* NULL these so if anything tries to use them, we'll know about it */
678   if(release_drawn) {
679     drawn_text = swap.text = NULL;
680     drawn_rend = swap.rend = NULL;
681     buf_text = NULL;
682     buf_rend = NULL;
683     buf_tlen = NULL;
684     tabs = NULL;
685   }
686 	screen[page].text = NULL;
687 	screen[page].rend = NULL;
688 	screen[page].tlen = NULL;
689 
690 }
691 
692 /* ------------------------------------------------------------------------- */
693 
pat_scr_remove(int page,int all)694 void pat_scr_remove(int page,int all) {
695   int i;
696 
697   f_scr_release(page,all);
698   for(i=page; i < TermWin.last_page; i++) {
699     screen[i] = screen[i+1];
700     prev_nrows[i] = prev_nrows[i];
701     prev_bcols[i] = prev_bcols[i];
702   }
703   // il faut reinitialiser prev_nrows et prev_bcols
704   prev_nrows[i] = prev_bcols[i] = -1;
705 }
706 
707 /* ------------------------------------------------------------------------- */
708 
f_scr_poweron(int page)709 void f_scr_poweron(int page)
710 {
711 	DSCR_ALEXIS(1,(stderr, "scr_poweron()\n"));
712 
713 	MEMSET(charsets, 'B', sizeof(charsets));
714 	rvideo = 0;
715 	swap.tscroll = 0;
716 	swap.bscroll = TermWin.nrow - 1;
717 	screen[page].cur.row = screen[page].cur.col = swap.cur.row = swap.cur.col = 0;
718 	screen[page].charset = swap.charset = 0;
719 	screen[page].flags = swap.flags = Screen_DefaultFlags;
720 
721 	f_scr_cursor(page,SAVE);
722 
723 	f_scr_release(page,0);
724 	prev_nrows[page] = -1;
725 	prev_bcols[page] = -1;
726 	f_scr_reset(page);
727 
728 	f_scr_clear(page);
729 	f_scr_refresh(page,SLOW_REFRESH);
730 
731 }
732 
733 /* ------------------------------------------------------------------------- *
734  *                         PROCESS SCREEN COMMANDS                           *
735  * ------------------------------------------------------------------------- */
736 /*
737  * Save and Restore cursor
738  * XTERM_SEQ: Save cursor   : ESC 7
739  * XTERM_SEQ: Restore cursor: ESC 8
740  */
741 
742 
743 
744 /* PROTO */
745 void
f_scr_cursor(int page,int mode)746 f_scr_cursor(int page,int mode)
747 {
748 	DSCR_ALEXIS(1,(stderr, "scr_cursor(%d,%d)\n", page,mode));
749 
750 	switch (mode)
751 	{
752 	case SAVE:
753 		save[page].cur.row = screen[page].cur.row;
754 		save[page].cur.col = screen[page].cur.col;
755 		save[page].rstyle = rstyle;
756 		save[page].charset = screen[page].charset;
757 		save[page].charset_char = charsets[screen[page].charset];
758 		break;
759 	case RESTORE:
760 		screen[page].cur.row = save[page].cur.row;
761 		screen[page].cur.col = save[page].cur.col;
762 		rstyle = save[page].rstyle;
763 		screen[page].charset = save[page].charset;
764 		charsets[screen[page].charset] = save[page].charset_char;
765 		f_set_font_style(page);
766 		break;
767 	}
768 /* boundary check in case screen size changed between SAVE and RESTORE */
769 	MIN_IT(screen[page].cur.row, TermWin.nrow - 1);
770 	MIN_IT(screen[page].cur.col, TermWin.vts[page].bcol - 1);
771 #ifdef DEBUG_STRICT
772 	assert(screen[page].cur.row >= 0);
773 	assert(screen[page].cur.col >= 0);
774 #else				/* drive with your eyes closed */
775 	MAX_IT(screen[page].cur.row, 0);
776 	MAX_IT(screen[page].cur.col, 0);
777 #endif
778 }
779 
780 /* ------------------------------------------------------------------------- */
781 /*
782  * Swap between primary and secondary screens
783  * XTERM_SEQ: Primary screen  : ESC [ ? 4 7 h
784  * XTERM_SEQ: Secondary screen: ESC [ ? 4 7 l
785  */
786 
787 
788 /* PROTO */
789 int
f_scr_change_screen(int page,int scrn)790 f_scr_change_screen(int page,int scrn)
791 {
792 	int             i, offset, tmp;
793 	text_t         *t0;
794 	rend_t         *r0;
795 	R_int16_t       l0;
796 
797 	DSCR_ALEXIS(1,(stderr, "scr_change_screen(%d)\n", scrn));
798 
799 	TermWin.vts[page].view_start = 0;
800 	RESET_CHSTAT;
801 
802 	if (current_screen == scrn)
803 		return current_screen;
804 
805   DSCR_ALEXIS(2,(stderr,"Gloups, continuing in change screen\n"));
806 	CHECK_SELECTION(pagepage,2);	/* check for boundary cross */
807 
808 	SWAP_IT(current_screen, scrn, tmp);
809 #if NSCREENS
810 	offset = TermWin.vts[page].saveLines;
811 	for (i = TermWin.nrow; i--;)
812 	{
813 		SWAP_IT(screen[page].text[i + offset], swap.text[i], t0);
814 		SWAP_IT(screen[page].tlen[i + offset], swap.tlen[i], l0);
815 		SWAP_IT(screen[page].rend[i + offset], swap.rend[i], r0);
816 	}
817 	SWAP_IT(screen[page].cur.row, swap.cur.row, l0);
818 	SWAP_IT(screen[page].cur.col, swap.cur.col, l0);
819 # ifdef DEBUG_STRICT
820 	assert(screen[page].cur.row >= 0);
821 	assert(screen[page].cur.col >= 0);
822 	assert(screen[page].cur.row < TermWin.nrow);
823 	assert(screen[page].cur.col < TermWin.vts[page].bcol);
824 # else				/* drive with your eyes closed */
825 	MAX_IT(screen[page].cur.row, 0);
826 	MAX_IT(screen[page].cur.col, 0);
827 	MIN_IT(screen[page].cur.row, TermWin.nrow - 1);
828 	MIN_IT(screen[page].cur.col, TermWin.vts[page].bcol - 1);
829 # endif
830 	SWAP_IT(screen[page].charset, swap.charset, l0);
831 	SWAP_IT(screen[page].flags, swap.flags, tmp);
832 	screen[page].flags |= Screen_VisibleCursor;
833 	swap.flags |= Screen_VisibleCursor;
834 
835 #else
836 # ifndef DONT_SCROLL_ME
837 	if (current_screen == PRIMARY)
838 	{
839 
840 		f_scroll_text(page,0, (TermWin.nrow - 1), TermWin.nrow, 0);
841 		for (i = TermWin.vts[page].saveLines;
842 		     i < TermWin.nrow + TermWin.vts[page].saveLines; i++)
843 			if (screen[page].text[i] == NULL)
844 			{
845 				f_make_screen_mem(page,screen[page].text, screen[page].rend, i,DEFAULT_RSTYLE);
846 				screen[page].tlen[i] = 0;
847 			}
848 	}
849 # endif
850 #endif
851 	return scrn;
852 }
853 
854 /* ------------------------------------------------------------------------- */
855 /*
856  * Change the colour for following text
857  */
858 /* PROTO */
859 void
scr_color(unsigned int color,unsigned int Intensity)860 scr_color(unsigned int color, unsigned int Intensity)
861 {
862 	if (color == restoreFG)
863 		color = Color_fg;
864 	else if (color == restoreBG)
865 		color = Color_bg;
866 	else
867 	{
868 		if (Xdepth <= 2)
869 		{		/* Monochrome - ignore colour changes */
870 			switch (Intensity)
871 			{
872 			case RS_Bold:
873 				color = Color_fg;
874 				break;
875 			case RS_Blink:
876 				color = Color_bg;
877 				break;
878 			}
879 		} else
880 		{
881 #ifndef NO_BRIGHTCOLOR
882 			if ((rstyle & Intensity) && color >= minCOLOR
883 			    && color <= maxCOLOR)
884 				color += (minBrightCOLOR - minCOLOR);
885 			else if (color >= minBrightCOLOR
886 				 && color <= maxBrightCOLOR)
887 			{
888 				if (rstyle & Intensity)
889 					return;
890 				color -= (minBrightCOLOR - minCOLOR);
891 			}
892 #endif
893 		}
894 	}
895 	switch (Intensity)
896 	{
897 	case RS_Bold:
898 		rstyle = SET_FGCOLOR(rstyle, color);
899 		break;
900 	case RS_Blink:
901 		rstyle = SET_BGCOLOR(rstyle, color);
902 		break;
903 	}
904 }
905 
906 /* ------------------------------------------------------------------------- */
907 /*
908  * Change the rendition style for following text
909  */
910 /* PROTO */
911 void
scr_rendition(int set,int style)912 scr_rendition(int set, int style)
913 {
914 	unsigned int    color;
915 	rend_t          font_attr;
916 
917 	if (set)
918 	{
919 /* A: Set style */
920 		rstyle |= style;
921 		switch (style)
922 		{
923 		case RS_RVid:
924 			if (rvideo)
925 				rstyle &= ~RS_RVid;
926 			break;
927 #ifndef NO_BRIGHTCOLOR
928 		case RS_Bold:
929 			color = GET_FGCOLOR(rstyle);
930 			scr_color((color == Color_fg ? GET_FGCOLOR(colorfgbg) : color),RS_Bold);
931 			break;
932 		case RS_Blink:
933 			color = GET_BGCOLOR(rstyle);
934 			scr_color((color == Color_bg ? GET_BGCOLOR(colorfgbg) : color),RS_Blink);
935 			break;
936 #endif
937 		}
938 	} else
939 	{
940 /* B: Unset style */
941 		font_attr = rstyle & RS_fontMask;
942 		rstyle &= ~style;
943 
944 		switch (style)
945 		{
946 		case ~RS_None:	/* default fg/bg colours */
947 			rstyle = DEFAULT_RSTYLE | font_attr;
948 		    /* FALLTHROUGH */
949 		case RS_RVid:
950 			if (rvideo)
951 				rstyle |= RS_RVid;
952 			break;
953 #ifndef NO_BRIGHTCOLOR
954 		case RS_Bold:
955 			color = GET_FGCOLOR(rstyle);
956 			if (color >= minBrightCOLOR && color <= maxBrightCOLOR)
957 			{
958 				scr_color(color, RS_Bold);
959 				if ((rstyle & RS_fgMask) == (colorfgbg & RS_fgMask))
960 					scr_color(restoreFG, RS_Bold);
961 			}
962 			break;
963 		case RS_Blink:
964 			color = GET_BGCOLOR(rstyle);
965 			if (color >= minBrightCOLOR && color <= maxBrightCOLOR)
966 			{
967 				scr_color(color, RS_Blink);
968 				if ((rstyle & RS_bgMask) == (colorfgbg & RS_bgMask))
969 					scr_color(restoreBG, RS_Blink);
970 			}
971 			break;
972 #endif
973 		}
974 	}
975 }
976 
977 /* ------------------------------------------------------------------------- */
978 /*
979  * Scroll text between <row1> and <row2> inclusive, by <count> lines
980  * count positive ==> scroll up
981  * count negative ==> scroll down
982  * spec == 0 for normal routines
983  */
984 
985 
986 /* PROTO */
987 int
f_scroll_text(int page,int row1,int row2,int count,int spec)988 f_scroll_text(int page,int row1, int row2, int count, int spec)
989 {
990 	int             i, j;
991 
992   DSCR_ALEXIS(1,(stderr, "f_scroll_text(%d,%d,%d,%d,%d): %s\n", page,row1, row2, count,
993     spec,(current_screen == PRIMARY) ? "Primary" : "Secondary"));
994 
995   if (count == 0 || (row1 > row2))
996     return 0;
997 
998   if ((count > 0) && (row1 == 0) && (current_screen == PRIMARY)) {
999     DSCR_ALEXIS(2,(stderr,"TermWin.nscrolled = %d, TermWin.saveLines = %d\n",
1000       TermWin.vts[page].nscrolled,TermWin.vts[page].saveLines));
1001     TermWin.vts[page].nscrolled += count;
1002     MIN_IT(TermWin.vts[page].nscrolled, TermWin.vts[page].saveLines);
1003 
1004   } else if (!spec)
1005     row1 += TermWin.vts[page].saveLines;
1006   row2 += TermWin.vts[page].saveLines;
1007 
1008   DSCR_ALEXIS(2,(stderr, "scroll_text(...) -> %d,%d\n",row1,row2));
1009 
1010   if (selection.op && current_screen == selection.screen && page == selection.vt)
1011   {
1012     i = selection.beg.row + TermWin.vts[page].saveLines;
1013     j = selection.end.row + TermWin.vts[page].saveLines;
1014     if ((i < row1 && j > row1)
1015         || (i < row2 && j > row2)
1016         || (i - count < row1 && i >= row1)
1017         || (i - count > row2 && i <= row2)
1018         || (j - count < row1 && j >= row1)
1019         || (j - count > row2 && j <= row2))
1020     {
1021       CLEAR_ALL_SELECTION;
1022       selection.op = SELECTION_CLEAR;	/* XXX: too aggressive? */
1023     } else if (j >= row1 && j <= row2)
1024     {
1025         /* move selected region too */
1026       selection.beg.row -= count;
1027       selection.end.row -= count;
1028       selection.mark.row -= count;
1029     }
1030   }
1031   CHECK_SELECTION(pagepage,0);	/* _after_ TermWin.nscrolled update */
1032 
1033   if (count > 0)
1034   {
1035 /* A: scroll up */
1036 
1037     // on prend le min entre count et le nbr de lignes entre row1 et row2
1038 		MIN_IT(count, row2 - row1 + 1);
1039 /* A1: Copy lines that will get clobbered by the rotation */
1040     for (i = 0, j = row1; i < count; i++, j++)
1041     {
1042       buf_text[i] = screen[page].text[j];
1043       buf_tlen[i] = screen[page].tlen[j];
1044       buf_rend[i] = screen[page].rend[j];
1045     }
1046 /* A2: Rotate lines */
1047     for (j = row1; (j + count) <= row2; j++)
1048     {
1049       screen[page].text[j] = screen[page].text[j + count];
1050       screen[page].tlen[j] = screen[page].tlen[j + count];
1051       screen[page].rend[j] = screen[page].rend[j + count];
1052     }
1053 /* A3: Resurrect lines */
1054 		for (i = 0; i < count; i++, j++)
1055 		{
1056 			screen[page].text[j] = buf_text[i];
1057 			screen[page].tlen[j] = buf_tlen[i];
1058 			screen[page].rend[j] = buf_rend[i];
1059 		}
1060 	} else if (count < 0)
1061 	{
1062 /* B: scroll down */
1063 
1064 		count = min(-count, row2 - row1 + 1);
1065 /* B1: Copy lines that will get clobbered by the rotation */
1066 		for (i = 0, j = row2; i < count; i++, j--)
1067 		{
1068 			buf_text[i] = screen[page].text[j];
1069 			buf_tlen[i] = screen[page].tlen[j];
1070 			buf_rend[i] = screen[page].rend[j];
1071 		}
1072 /* B2: Rotate lines */
1073 		for (j = row2; (j - count) >= row1; j--)
1074 		{
1075 			screen[page].text[j] = screen[page].text[j - count];
1076 			screen[page].tlen[j] = screen[page].tlen[j - count];
1077 			screen[page].rend[j] = screen[page].rend[j - count];
1078 		}
1079 /* B3: Resurrect lines */
1080 		for (i = 0, j = row1; i < count; i++, j++)
1081 		{
1082 			screen[page].text[j] = buf_text[i];
1083 			screen[page].tlen[j] = buf_tlen[i];
1084 			screen[page].rend[j] = buf_rend[i];
1085 		}
1086 		count = -count;
1087 	}
1088 	return count;
1089 }
1090 
1091 /* ------------------------------------------------------------------------- */
1092 /*
1093  * Add text given in <str> of length <len> to screen struct
1094  */
1095 
1096 
1097 /* PROTO */
1098 void
f_scr_add_lines(int page,const unsigned char * str,int nlines,int len)1099 f_scr_add_lines(int page,const unsigned char *str, int nlines, int len)
1100 {
1101 	char            c;
1102 	int             i, j, row, last_col, wherecursor, wrotespecial;
1103 	text_t         *stp;
1104 	rend_t         *srp;
1105 
1106 	if (len <= 0)		/* sanity */
1107 		return;
1108 
1109 	last_col = TermWin.vts[page].bcol;
1110 
1111 	DSCR_ALEXIS(2,(stderr, "scr_add_lines(%d,%d,%d), screen.bscroll:%d,bcol:%d\n",
1112     page,nlines, len,screen[page].bscroll,last_col));
1113   DSCR_ALEXIS(2,(stderr, "cursor(%d,%d)\n",screen[page].cur.row,screen[page].cur.col));
1114 	f_ZERO_SCROLLBACK(page);
1115 	if (nlines > 0)
1116 	{
1117     // nombre de lignes entre le curseur et bscroll
1118 		nlines += (screen[page].cur.row - screen[page].bscroll);
1119 		if ((nlines > 0) && (screen[page].tscroll == 0) && (screen[page].bscroll == (TermWin.nrow - 1)))
1120 		{
1121 		    /* _at least_ this many lines need to be scrolled */
1122 			f_scroll_text(page,screen[page].tscroll, screen[page].bscroll, nlines, 0);
1123 			for (i = nlines, j = screen[page].bscroll + TermWin.vts[page].saveLines; i--; j--)
1124 			{
1125 				if (screen[page].text[j] == NULL)
1126 					f_make_screen_mem(page,screen[page].text,screen[page].rend, j,rstyle);
1127 				else
1128 					blank_line(screen[page].text[j], screen[page].rend[j], TermWin.vts[page].bcol, rstyle);
1129 				screen[page].tlen[j] = 0;
1130 			}
1131 			screen[page].cur.row -= nlines;
1132 		}
1133 	}
1134 #ifdef DEBUG_STRICT
1135 	assert(screen[page].cur.col < last_col);
1136 	assert(screen[page].cur.row < TermWin.nrow);
1137 	assert(screen[page].cur.row >= -TermWin.vts[page].nscrolled);
1138 #else				/* drive with your eyes closed */
1139 	MIN_IT(screen[page].cur.col, last_col - 1);
1140 	MIN_IT(screen[page].cur.row, TermWin.nrow - 1);
1141 	MAX_IT(screen[page].cur.row, -TermWin.vts[page].nscrolled);
1142 #endif
1143 	row = screen[page].cur.row + TermWin.vts[page].saveLines;
1144 
1145 	if (ROW_AND_COL_IS_BEFORE(screen[page].cur.row, screen[page].cur.col,
1146 				  selection.beg.row, selection.beg.col))
1147 		wherecursor = -1;
1148 	else if (ROW_AND_COL_IS_BEFORE(screen[page].cur.row, screen[page].cur.col,
1149 				       selection.end.row, selection.end.col))
1150 		wherecursor = 0;
1151 	else
1152 		wherecursor = 1;
1153 
1154 	stp = screen[page].text[row];
1155 	srp = screen[page].rend[row];
1156 
1157 #ifdef MULTICHAR_SET
1158 	if (lost_multi && screen[page].cur.col > 0
1159 	    && ((srp[screen[page].cur.col - 1] & RS_multiMask) == RS_multi1)
1160 	    && *str != '\n' && *str != '\r' && *str != '\t')
1161 		chstat = WBYTE;
1162 #endif
1163 
1164 	for (wrotespecial = len, i = 0; i < len;)
1165 	{
1166 		c = str[i++];
1167 #ifdef MULTICHAR_SET
1168 		if (chstat == WBYTE)
1169 		{
1170 			rstyle |= RS_multiMask;	/* multibyte 2nd byte */
1171 			chstat = SBYTE;
1172 			if (encoding_method == EUCJ)
1173 				c |= 0x80;	/* maybe overkill, but makes it selectable */
1174 		} else if (chstat == SBYTE)
1175 			if (multi_byte || (c & 0x80))
1176 			{	/* multibyte 1st byte */
1177 				rstyle &= ~RS_multiMask;
1178 				rstyle |= RS_multi1;
1179 				chstat = WBYTE;
1180 				if (encoding_method == EUCJ)
1181 					c |= 0x80;	/* maybe overkill, but makes it selectable */
1182 			} else
1183 #endif				/* MULTICHAR_SET */
1184 				switch (c)
1185 				{
1186 				case 127:
1187 					wrotespecial--;
1188 					continue;	/* yummmm..... */
1189 				case '\t':
1190 					wrotespecial--;
1191 					f_scr_tab(page,1);
1192 					continue;
1193 				case '\n':
1194 					wrotespecial--;
1195 					if (screen[page].tlen[row] != -1)	/* XXX: think about this */
1196 						MAX_IT(screen[page].tlen[row],screen[page].cur.col);
1197 					screen[page].flags &= ~Screen_WrapNext;
1198 					if (screen[page].cur.row == screen[page].bscroll)
1199 					{
1200 						f_scroll_text(page,screen[page].tscroll, screen[page].bscroll, 1, 0);
1201 						j = screen[page].bscroll + TermWin.vts[page].saveLines;
1202 						if (screen[page].text[j] == NULL)
1203 							f_make_screen_mem(page,screen[page].text,screen[page].rend,j,rstyle);
1204 						else
1205 							blank_line(screen[page].text[j],screen[page].rend[j],TermWin.vts[page].bcol,rstyle);
1206               screen[page].tlen[j] = 0;
1207 					} else if (screen[page].cur.row < (TermWin.nrow - 1))
1208 						row = (++screen[page].cur.row) + TermWin.vts[page].saveLines;
1209 					stp = screen[page].text[row];	/* _must_ refresh */
1210 					srp = screen[page].rend[row];	/* _must_ refresh */
1211 					continue;
1212 				case '\r':
1213 					wrotespecial--;
1214 					if (screen[page].tlen[row] != -1)	/* XXX: think about this */
1215 						MAX_IT(screen[page].tlen[row], screen[page].cur.col);
1216 					screen[page].flags &= ~Screen_WrapNext;
1217 					screen[page].cur.col = 0;
1218 					continue;
1219 				default:
1220 #ifdef MULTICHAR_SET
1221 					rstyle &= ~RS_multiMask;
1222 #endif
1223 					break;
1224 				}
1225 		if (screen[page].flags & Screen_WrapNext)
1226 		{
1227 			screen[page].tlen[row] = -1;
1228 			if (screen[page].cur.row == screen[page].bscroll)
1229 			{
1230 				f_scroll_text(page,screen[page].tscroll, screen[page].bscroll, 1,0);
1231 				j = screen[page].bscroll + TermWin.vts[page].saveLines;
1232 				if (screen[page].text[j] == NULL)
1233 					f_make_screen_mem(page,screen[page].text,screen[page].rend, j,rstyle);
1234 				else
1235 					blank_line(screen[page].text[j],screen[page].rend[j],TermWin.vts[page].bcol, rstyle);
1236 				screen[page].tlen[j] = 0;
1237 			} else if (screen[page].cur.row < (TermWin.nrow - 1))
1238 				row = (++screen[page].cur.row) + TermWin.vts[page].saveLines;
1239 			stp = screen[page].text[row];	/* _must_ refresh */
1240 			srp = screen[page].rend[row];	/* _must_ refresh */
1241 			screen[page].cur.col = 0;
1242 			screen[page].flags &= ~Screen_WrapNext;
1243 		}
1244 		if (screen[page].flags & Screen_Insert)
1245 			f_scr_insdel_chars(page,1, INSERT);
1246 		stp[screen[page].cur.col] = c;
1247 		srp[screen[page].cur.col] = rstyle;
1248 	    /*
1249 	     * TODO: This might end up wrapping the tone sign in Thai
1250 	     */
1251 		if (screen[page].cur.col < (last_col - 1))
1252 			screen[page].cur.col++;
1253 		else
1254 		{
1255 			screen[page].tlen[row] = last_col;
1256 			if (screen[page].flags & Screen_Autowrap)
1257 				screen[page].flags |= Screen_WrapNext;
1258 			else
1259 				screen[page].flags &= ~Screen_WrapNext;
1260 		}
1261 	}
1262 	if (screen[page].tlen[row] != -1)	/* XXX: think about this */
1263 		MAX_IT(screen[page].tlen[row], screen[page].cur.col);
1264 
1265 /*
1266  * If we wrote anywhere in the selected area, kill the selection
1267  * XXX: should we kill the mark too?  Possibly, but maybe that
1268  *      should be a similar check.
1269  */
1270 	if (ROW_AND_COL_IS_BEFORE(screen[page].cur.row, screen[page].cur.col,
1271 				  selection.beg.row, selection.beg.col))
1272 		i = -1;
1273 	else if (ROW_AND_COL_IS_BEFORE(screen[page].cur.row, screen[page].cur.col,
1274 				       selection.end.row, selection.end.col))
1275 		i = 0;
1276 	else
1277 		i = 1;
1278 	if (selection.op && current_screen == selection.screen
1279 	    && wrotespecial != 0 && (i != wherecursor || i == 0))
1280 		CLEAR_SELECTION;
1281 
1282 #ifdef DEBUG_STRICT
1283 	assert(screen[page].cur.row >= 0);
1284 #else				/* drive with your eyes closed */
1285 	MAX_IT(screen[page].cur.row, 0);
1286 #endif
1287 }
1288 
1289 
1290 
1291 
1292 /* ------------------------------------------------------------------------- */
1293 /*
1294  * Process Backspace.  Move back the cursor back a position, wrap if have to
1295  * XTERM_SEQ: CTRL-H
1296  */
1297 
1298 
f_scr_backspace(int page)1299 void f_scr_backspace(int page)
1300 {
1301 	RESET_CHSTAT;
1302   DSCR_ALEXIS(2,(stderr,"f_scr_backspace(%d)\n",page));
1303 	if (screen[page].cur.col == 0 && screen[page].cur.row > 0)
1304 	{
1305 		screen[page].cur.col = TermWin.vts[page].bcol - 1;
1306 		screen[page].cur.row--;
1307 	} else if (screen[page].flags & Screen_WrapNext)
1308 	{
1309 		screen[page].flags &= ~Screen_WrapNext;
1310 	} else
1311 		f_scr_gotorc(page,0, -1, RELATIVE);
1312 }
1313 
1314 /* ------------------------------------------------------------------------- */
1315 /*
1316  * Process Horizontal Tab
1317  * count: +ve = forward; -ve = backwards
1318  * XTERM_SEQ: CTRL-I
1319  */
1320 
f_scr_tab(int page,int count)1321 void f_scr_tab(int page,int count)
1322 {
1323 	int             i, x;
1324 
1325 	RESET_CHSTAT;
1326   DSCR_ALEXIS(2,(stderr,"f_scr_tab(...)\n"));
1327 	x = screen[page].cur.col;
1328 	if (count == 0)
1329 		return;
1330 	else if (count > 0)
1331 	{
1332 		for (i = x + 1; i < TermWin.vts[page].bcol; i++)
1333 		{
1334 			if (tabs[i])
1335 			{
1336 				x = i;
1337 				if (!--count)
1338 					break;
1339 			}
1340 		}
1341 	} else if (count < 0)
1342 	{
1343 		for (i = x - 1; i >= 0; i--)
1344 		{
1345 			if (tabs[i])
1346 			{
1347 				x = i;
1348 				if (!++count)
1349 					break;
1350 			}
1351 		}
1352 	}
1353 	if (x != screen[page].cur.col)
1354 		f_scr_gotorc(page,0, x, R_RELATIVE);
1355 }
1356 
1357 /* ------------------------------------------------------------------------- */
1358 /*
1359  * Goto Row/Column
1360  */
1361 
1362 
1363 /* PROTO */
1364 void
f_scr_gotorc(int page,int row,int col,int relative)1365 f_scr_gotorc(int page,int row, int col, int relative)
1366 {
1367 	f_ZERO_SCROLLBACK(page);
1368 	RESET_CHSTAT;
1369 	DSCR_ALEXIS(1,(stderr, "scr_gotorc(r:%d,c:%d,%d): from (r:%d,c:%d), bcol:%d\n", row,
1370     col, relative, screen[page].cur.row, screen[page].cur.col,TermWin.vts[page].bcol));
1371 
1372 	screen[page].cur.col = ((relative & C_RELATIVE) ? (screen[page].cur.col + col) : col);
1373 	MAX_IT(screen[page].cur.col, 0); // 0 <= screen[0].cur.col <= col
1374 	MIN_IT(screen[page].cur.col, TermWin.vts[page].bcol - 1);
1375 
1376 	if (screen[page].flags & Screen_WrapNext)
1377 	{
1378 		screen[page].flags &= ~Screen_WrapNext;
1379 	}
1380 	if (relative & R_RELATIVE)
1381 	{
1382 		if (row > 0)
1383 		{
1384 			if (screen[page].cur.row <= screen[page].bscroll &&
1385         (screen[page].cur.row + row) > screen[page].bscroll)
1386 				screen[page].cur.row = screen[page].bscroll;
1387 			else
1388 				screen[page].cur.row += row;
1389 		} else if (row < 0)
1390 		{
1391 			if (screen[page].cur.row >= screen[page].tscroll  &&
1392         (screen[page].cur.row + row) < screen[page].tscroll)
1393 				screen[page].cur.row = screen[page].tscroll;
1394 			else
1395 				screen[page].cur.row += row;
1396 		}
1397 	} else
1398 	{
1399 		if (screen[page].flags & Screen_Relative)
1400 		{		/* relative origin mode */
1401 			screen[page].cur.row = row + screen[page].tscroll;
1402 			MIN_IT(screen[page].cur.row, screen[page].bscroll);
1403 		} else
1404 			screen[page].cur.row = row;
1405 	}
1406 	MAX_IT(screen[page].cur.row, 0);
1407 	MIN_IT(screen[page].cur.row, TermWin.nrow - 1);
1408 }
1409 
1410 /* ------------------------------------------------------------------------- */
1411 /*
1412  * direction  should be UP or DN
1413  */
1414 
1415 
1416 /* PROTO */
1417 void
f_scr_index(int page,int direction)1418 f_scr_index(int page,int direction)
1419 {
1420 	int dirn;
1421 
1422 	dirn = ((direction == UP) ? 1 : -1);
1423 	DSCR_ALEXIS(1,(stderr, "scr_index(%d)\n", dirn));
1424 
1425 	f_ZERO_SCROLLBACK(page);
1426 	RESET_CHSTAT;
1427 	if (screen[page].flags & Screen_WrapNext)
1428 	{
1429 		screen[page].flags &= ~Screen_WrapNext;
1430 	}
1431 	if ((screen[page].cur.row == screen[page].bscroll && direction == UP)
1432 	    || (screen[page].cur.row == screen[page].tscroll && direction == DN))
1433 	{
1434 		f_scroll_text(page,screen[page].tscroll, screen[page].bscroll, dirn, 0);
1435 		if (direction == UP)
1436 			dirn = screen[page].bscroll + TermWin.vts[page].saveLines;
1437 		else
1438 			dirn = screen[page].tscroll + TermWin.vts[page].saveLines;
1439 		if (screen[page].text[dirn] == NULL)	/* then so is screen[0].rend[dirn] */
1440 			f_make_screen_mem(page,screen[page].text, screen[page].rend, dirn,rstyle);
1441 		else
1442 			blank_line(screen[page].text[dirn], screen[page].rend[dirn],TermWin.vts[page].bcol, rstyle);
1443 		screen[page].tlen[dirn] = 0;
1444 	} else
1445 		screen[page].cur.row += dirn;
1446 
1447 	MAX_IT(screen[page].cur.row, 0);
1448 	MIN_IT(screen[page].cur.row, TermWin.nrow - 1);
1449 	CHECK_SELECTION(pagepage,0);
1450 }
1451 
1452 /* ------------------------------------------------------------------------- */
1453 /*
1454  * Erase part or whole of a line
1455  * XTERM_SEQ: Clear line to right: ESC [ 0 K
1456  * XTERM_SEQ: Clear line to left : ESC [ 1 K
1457  * XTERM_SEQ: Clear whole line   : ESC [ 2 K
1458  */
1459 
1460 
1461 /* PROTO */
1462 void
f_scr_erase_line(int page,int mode)1463 f_scr_erase_line(int page,int mode)
1464 {
1465 	int             row, col, num;
1466 
1467 	DSCR_ALEXIS(2,(stderr, "scr_erase_line(%d,%d) at screen row: %d\n", page,mode,
1468 		  screen[page].cur.row));
1469 	f_ZERO_SCROLLBACK(page);
1470 	RESET_CHSTAT;
1471 	CHECK_SELECTION(pagepage,1);
1472 
1473 	if (screen[page].flags & Screen_WrapNext)
1474 		screen[page].flags &= ~Screen_WrapNext;
1475 
1476 	row = TermWin.vts[page].saveLines + screen[page].cur.row;
1477 	switch (mode)
1478 	{
1479 	case 0:		/* erase to end of line */
1480 		col = screen[page].cur.col;
1481 		num = TermWin.vts[page].bcol - col;
1482 		MIN_IT(screen[page].tlen[row], col);
1483     // pour voir si la ligne qu'on va effacer contient la selection ou pas
1484 		if (ROWCOL_IN_ROW_ON_OR_AFTER(selection.beg, screen[page].cur)
1485 		    || ROWCOL_IN_ROW_ON_OR_AFTER(selection.end, screen[page].cur))
1486 			CLEAR_SELECTION;
1487 		break;
1488 	case 1:		/* erase to beginning of line */
1489 		col = 0;
1490 		num = screen[page].cur.col + 1;
1491 		if (ROWCOL_IN_ROW_ON_OR_BEFORE(selection.beg, screen[page].cur)
1492 		    || ROWCOL_IN_ROW_ON_OR_BEFORE(selection.end, screen[page].cur))
1493 			CLEAR_SELECTION;
1494 		break;
1495 	case 2:		/* erase whole line */
1496 		col = 0;
1497 		num = TermWin.vts[page].bcol;
1498 		screen[page].tlen[row] = 0;
1499 		if (selection.beg.row <= screen[page].cur.row
1500 		    || selection.end.row >= screen[page].cur.row)
1501 			CLEAR_SELECTION;
1502 		break;
1503 	default:
1504 		return;
1505 	}
1506 	blank_line(&(screen[page].text[row][col]), &(screen[page].rend[row][col]), num,
1507 		   rstyle & ~RS_Uline);
1508 }
1509 
1510 /* ------------------------------------------------------------------------- */
1511 /*
1512  * Erase part of whole of the screen
1513  * XTERM_SEQ: Clear screen after cursor : ESC [ 0 J
1514  * XTERM_SEQ: Clear screen before cursor: ESC [ 1 J
1515  * XTERM_SEQ: Clear whole screen        : ESC [ 2 J
1516  */
1517 
1518 
1519 /* PROTO */
1520 void
f_scr_erase_screen(int page,int mode)1521 f_scr_erase_screen(int page,int mode)
1522 {
1523 	int             row, num, row_offset;
1524 	rend_t          ren;
1525 	long            gcmask;
1526 	XGCValues       gcvalue;
1527 
1528 	DSCR_ALEXIS(1,(stderr, "scr_erase_screen(%d) at screen row: %d\n",
1529     mode,screen[page].cur.row));
1530 	f_ZERO_SCROLLBACK(page);
1531 	RESET_CHSTAT;
1532 //	row_offset = TermWin.vts[TermWin.active_page].saveLines;
1533 	row_offset = TermWin.vts[page].saveLines;
1534 
1535 	switch (mode)
1536 	{
1537 	case 0:		/* erase to end of screen */
1538 		CHECK_SELECTION(pagepage,1);
1539 		f_scr_erase_line(page,0);
1540 		row = screen[page].cur.row + 1;	/* possible OOB */
1541 		num = TermWin.nrow - row;
1542 		break;
1543 	case 1:		/* erase to beginning of screen */
1544 		CHECK_SELECTION(pagepage,3);
1545 		f_scr_erase_line(page,1);
1546 		row = 0;	/* possible OOB */
1547 		num = screen[page].cur.row;
1548 		break;
1549 	case 2:		/* erase whole screen */
1550 		CHECK_SELECTION(pagepage,3);
1551 		row = 0;
1552 		num = TermWin.nrow;
1553 		break;
1554 	default:
1555 		return;
1556 	}
1557 	if (selection.op && current_screen == selection.screen
1558     && selection.vt == page
1559 	    && ((selection.beg.row >= row
1560 		 && selection.beg.row <= row + num)
1561 		|| (selection.end.row >= row
1562 		    && selection.end.row <= row + num)))
1563 		CLEAR_SELECTION;
1564 	if (row >= 0 && row < TermWin.nrow)
1565 	{			/* check OOB */
1566 		MIN_IT(num, (TermWin.nrow - row));
1567 		if (rstyle & (RS_RVid | RS_Uline))
1568 			ren = (rend_t) ~ RS_None;
1569 		else if (GET_BGCOLOR(rstyle) == Color_bg)
1570 		{
1571 			ren = DEFAULT_RSTYLE;
1572 			f_CLEAR_ROWS(page,row, num);
1573 		} else
1574 		{
1575 			ren = (rstyle & (RS_fgMask | RS_bgMask));
1576 			gcvalue.foreground = PixColors[GET_BGCOLOR(ren)];
1577 			gcmask = GCForeground;
1578 			XChangeGC(Xdisplay, TermWin.vts[page].gc, gcmask, &gcvalue);
1579 			f_ERASE_ROWS(page,row, num);
1580 			gcvalue.foreground = PixColors[Color_fg];
1581 			XChangeGC(Xdisplay, TermWin.vts[page].gc, gcmask, &gcvalue);
1582 		}
1583 		for (; num--; row++)
1584 		{
1585 			blank_line(screen[page].text[row + row_offset],
1586         screen[page].rend[row + row_offset], TermWin.vts[page].bcol,
1587         rstyle & ~RS_Uline);
1588 			screen[page].tlen[row + row_offset] = 0;
1589 			blank_line(drawn_text[row], drawn_rend[row],TermWin.vts[page].bcol, ren);
1590 		}
1591 	}
1592 }
1593 
1594 /* ------------------------------------------------------------------------- */
1595 /*
1596  * Fill the screen with `E's
1597  * XTERM_SEQ: Screen Alignment Test: ESC # 8
1598  */
1599 
1600 /* PROTO */
1601 void
f_scr_E(int page)1602 f_scr_E(int page)
1603 {
1604 	int             i, j;
1605 	text_t         *t;
1606 	rend_t         *r, fs;
1607 
1608 	f_ZERO_SCROLLBACK(page);
1609 	RESET_CHSTAT;
1610 	CHECK_SELECTION(pagepage,3);
1611 
1612 	fs = rstyle;
1613 	for (i = TermWin.vts[page].saveLines; i < TermWin.nrow + TermWin.vts[page].saveLines; i++)
1614 	{
1615 		t = screen[page].text[i];
1616 		r = screen[page].rend[i];
1617 		for (j = 0; j < TermWin.vts[page].bcol; j++)
1618 		{
1619 			*t++ = 'E';
1620 			*r++ = fs;
1621 		}
1622 		screen[page].tlen[i] = TermWin.vts[page].bcol;	/* make the `E's selectable */
1623 	}
1624 }
1625 
1626 /* ------------------------------------------------------------------------- */
1627 /*
1628  * Insert/Delete <count> lines
1629  */
1630 
1631 /* PROTO */
1632 void
f_scr_insdel_lines(int page,int count,int insdel)1633 f_scr_insdel_lines(int page,int count, int insdel)
1634 {
1635 	int             end;
1636 
1637 	f_ZERO_SCROLLBACK(page);
1638 	RESET_CHSTAT;
1639 	CHECK_SELECTION(pagepage,1);
1640 
1641 	if (screen[page].cur.row > screen[page].bscroll)
1642 		return;
1643 
1644 	end = screen[page].bscroll - screen[page].cur.row + 1;
1645 	if (count > end)
1646 	{
1647 		if (insdel == DELETE)
1648 			return;
1649 		else if (insdel == INSERT)
1650 			count = end;
1651 	}
1652 	if (screen[page].flags & Screen_WrapNext)
1653 	{
1654 		screen[page].flags &= ~Screen_WrapNext;
1655 	}
1656 	f_scroll_text(page,screen[page].cur.row, screen[page].bscroll, insdel * count, 0);
1657 
1658 /* fill the inserted or new lines with rstyle. TODO: correct for delete? */
1659 	if (insdel == DELETE)
1660 	{
1661 		end = screen[page].bscroll + TermWin.vts[page].saveLines;
1662 	} else if (insdel == INSERT)
1663 	{
1664 		end = screen[page].cur.row + count - 1 + TermWin.vts[page].saveLines;
1665 	}
1666 	for (; count--; end--)
1667 	{
1668 		if (screen[page].text[end] == NULL)	/* then so is screen[0].rend[end] */
1669 			f_make_screen_mem(page,screen[page].text, screen[page].rend, end, rstyle);
1670 		else
1671 			blank_line(screen[page].text[end], screen[page].rend[end],
1672 				   TermWin.vts[page].bcol, rstyle);
1673 		screen[page].tlen[end] = 0;
1674 	}
1675 }
1676 
1677 
1678 /* ------------------------------------------------------------------------- */
1679 /*
1680  * Insert/Delete <count> characters from the current position
1681  */
1682 
1683 
1684 /* PROTO */
1685 void
f_scr_insdel_chars(int page,int count,int insdel)1686 f_scr_insdel_chars(int page,int count, int insdel)
1687 {
1688 	int             col, row;
1689 	rend_t          tr;
1690 
1691 	f_ZERO_SCROLLBACK(page);
1692 	RESET_CHSTAT;
1693 	if (count <= 0)
1694 		return;
1695 	CHECK_SELECTION(pagepage,1);
1696 	MIN_IT(count, (TermWin.vts[page].bcol - screen[page].cur.col));
1697 
1698 	row = screen[page].cur.row + TermWin.vts[page].saveLines;
1699 	screen[page].flags &= ~Screen_WrapNext;
1700 
1701 	switch (insdel)
1702 	{
1703 	case INSERT:
1704 		for (col = TermWin.vts[page].bcol - 1; (col - count) >= screen[page].cur.col;
1705 		     col--)
1706 		{
1707 			screen[page].text[row][col] = screen[page].text[row][col - count];
1708 			screen[page].rend[row][col] = screen[page].rend[row][col - count];
1709 		}
1710 		if (screen[page].tlen[row] != -1)
1711 		{
1712 			screen[page].tlen[row] += count;
1713 			MIN_IT(screen[page].tlen[row], TermWin.vts[page].bcol);
1714 		}
1715 		if (selection.op && current_screen == selection.screen
1716 		    && ROWCOL_IN_ROW_ON_OR_AFTER(selection.beg, screen[page].cur))
1717 		{
1718 			if (selection.end.row != screen[page].cur.row
1719 			    || (selection.end.col + count >= TermWin.vts[page].bcol))
1720 				CLEAR_SELECTION;
1721 			else
1722 			{	/* shift selection */
1723 				selection.beg.col += count;
1724 				selection.mark.col += count;	/* XXX: yes? */
1725 				selection.end.col += count;
1726 			}
1727 		}
1728 		blank_line(&(screen[page].text[row][screen[page].cur.col]),
1729 			   &(screen[page].rend[row][screen[page].cur.col]), count, rstyle);
1730 		break;
1731 	case ERASE:
1732 		screen[page].cur.col += count;	/* don't worry if > TermWin.bcol */
1733 		CHECK_SELECTION(page,1);
1734 		screen[page].cur.col -= count;
1735 		blank_line(&(screen[page].text[row][screen[page].cur.col]),
1736 			   &(screen[page].rend[row][screen[page].cur.col]), count, rstyle);
1737 		break;
1738 	case DELETE:
1739 		tr = screen[page].rend[row][TermWin.vts[page].bcol - 1]
1740 		    & (RS_fgMask | RS_bgMask | RS_baseattrMask);
1741 		for (col = screen[page].cur.col; (col + count) < TermWin.vts[page].bcol; col++)
1742 		{
1743 			screen[page].text[row][col] = screen[page].text[row][col + count];
1744 			screen[page].rend[row][col] = screen[page].rend[row][col + count];
1745 		}
1746 		blank_line(&(screen[page].text[row][TermWin.vts[page].bcol - count]),
1747 			   &(screen[page].rend[row][TermWin.vts[page].bcol - count]),
1748 			   count, tr);
1749 		if (screen[page].tlen[row] == -1)	/* break line continuation */
1750 			screen[page].tlen[row] = TermWin.vts[page].bcol;
1751 		screen[page].tlen[row] -= count;
1752 		MAX_IT(screen[page].tlen[row], 0);
1753 		if (selection.op && current_screen == selection.screen
1754 		    && ROWCOL_IN_ROW_ON_OR_AFTER(selection.beg, screen[page].cur))
1755 		{
1756 			if (selection.end.row != screen[page].cur.row
1757 			    || (screen[page].cur.col >= selection.beg.col - count)
1758 			    || selection.end.col >= TermWin.vts[page].bcol)
1759 				CLEAR_SELECTION;
1760 			else
1761 			{
1762 			    /* shift selection */
1763 				selection.beg.col -= count;
1764 				selection.mark.col -= count;	/* XXX: yes? */
1765 				selection.end.col -= count;
1766 			}
1767 		}
1768 		break;
1769 	}
1770 #ifdef MULTICHAR_SET
1771 	if ((screen[page].rend[row][page] & RS_multiMask) == RS_multi2)
1772 	{
1773 		screen[page].rend[row][page] &= ~RS_multiMask;
1774 		screen[page].text[row][page] = ' ';
1775 	}
1776 	if ((screen[page].rend[row][TermWin.vts[page].bcol - 1] & RS_multiMask) == RS_multi1)
1777 	{
1778 		screen[page].rend[row][TermWin.vts[page].bcol - 1] &= ~RS_multiMask;
1779 		screen[page].text[row][TermWin.vts[page].bcol - 1] = ' ';
1780 	}
1781 #endif
1782 }
1783 
1784 /* ------------------------------------------------------------------------- */
1785 /*
1786  * Set the scrolling region
1787  * XTERM_SEQ: Set region <top> - <bot> inclusive: ESC [ <top> ; <bot> r
1788  */
1789 
1790 
1791 /* PROTO */
1792 void
f_scr_scroll_region(int page,int top,int bot)1793 f_scr_scroll_region(int page,int top, int bot)
1794 {
1795   DSCR_ALEXIS(2,(stderr,"f_scr_scroll_region(%d,%d,%d)\n",page,top,bot));
1796 	MAX_IT(top, 0);
1797 	MIN_IT(bot, TermWin.nrow - 1);
1798 	if (top > bot)
1799 		return;
1800 	screen[page].tscroll = top;
1801 	screen[page].bscroll = bot;
1802 	f_scr_gotorc(page,0, 0, 0);
1803 }
1804 
1805 /* ------------------------------------------------------------------------- */
1806 /*
1807  * Make the cursor visible/invisible
1808  * XTERM_SEQ: Make cursor visible  : ESC [ ? 25 h
1809  * XTERM_SEQ: Make cursor invisible: ESC [ ? 25 l
1810  */
1811 
1812 
1813 /* PROTO */
1814 void
f_scr_cursor_visible(int page,int mode)1815 f_scr_cursor_visible(int page,int mode)
1816 {
1817 	if (mode)
1818 		screen[page].flags |= Screen_VisibleCursor;
1819 	else
1820 		screen[page].flags &= ~Screen_VisibleCursor;
1821 }
1822 
1823 /* ------------------------------------------------------------------------- */
1824 /*
1825  * Set/unset automatic wrapping
1826  * XTERM_SEQ: Set Wraparound  : ESC [ ? 7 h
1827  * XTERM_SEQ: Unset Wraparound: ESC [ ? 7 l
1828  */
1829 
1830 
1831 /* PROTO */
1832 void
f_scr_autowrap(int page,int mode)1833 f_scr_autowrap(int page,int mode)
1834 {
1835 	if (mode)
1836 		screen[page].flags |= Screen_Autowrap;
1837 	else
1838 		screen[page].flags &= ~Screen_Autowrap;
1839 }
1840 
1841 /* ------------------------------------------------------------------------- */
1842 /*
1843  * Set/unset margin origin mode
1844  * Absolute mode: line numbers are counted relative to top margin of screen
1845  *      and the cursor can be moved outside the scrolling region.
1846  * Relative mode: line numbers are relative to top margin of scrolling region
1847  *      and the cursor cannot be moved outside.
1848  * XTERM_SEQ: Set Absolute: ESC [ ? 6 h
1849  * XTERM_SEQ: Set Relative: ESC [ ? 6 l
1850  */
1851 
1852 
1853 /* PROTO */
1854 void
f_scr_relative_origin(int page,int mode)1855 f_scr_relative_origin(int page,int mode)
1856 {
1857   DSCR_ALEXIS(2,(stderr,"f_scr_relative_origin(..)\n"));
1858 	if (mode)
1859 		screen[page].flags |= Screen_Relative;
1860 	else
1861 		screen[page].flags &= ~Screen_Relative;
1862 	f_scr_gotorc(page,0, 0, 0);
1863 }
1864 
1865 /* ------------------------------------------------------------------------- */
1866 /*
1867  * Set insert/replace mode
1868  * XTERM_SEQ: Set Insert mode : ESC [ ? 4 h
1869  * XTERM_SEQ: Set Replace mode: ESC [ ? 4 l
1870  */
1871 
1872 
1873 /* PROTO */
1874 void
f_scr_insert_mode(int page,int mode)1875 f_scr_insert_mode(int page,int mode)
1876 {
1877 	if (mode)
1878 		screen[page].flags |= Screen_Insert;
1879 	else
1880 		screen[page].flags &= ~Screen_Insert;
1881 }
1882 
1883 /* ------------------------------------------------------------------------- */
1884 /*
1885  * Set/Unset tabs
1886  * XTERM_SEQ: Set tab at current column  : ESC H
1887  * XTERM_SEQ: Clear tab at current column: ESC [ 0 g
1888  * XTERM_SEQ: Clear all tabs             : ESC [ 3 g
1889  */
1890 
1891 
1892 /* PROTO */
1893 void
f_scr_set_tab(int page,int mode)1894 f_scr_set_tab(int page,int mode)
1895 {
1896 	if (mode < 0)
1897 		MEMSET(tabs, 0, TermWin.vts[page].bcol * sizeof(char));
1898 
1899 	else if (screen[page].cur.col < TermWin.vts[page].bcol)
1900 		tabs[screen[page].cur.col] = (mode ? 1 : 0);
1901 }
1902 
1903 /* ------------------------------------------------------------------------- */
1904 /*
1905  * Set reverse/normal video
1906  * XTERM_SEQ: Reverse video: ESC [ ? 5 h
1907  * XTERM_SEQ: Normal video : ESC [ ? 5 l
1908  */
1909 /* PROTO */
1910 void
f_scr_rvideo_mode(int page,int mode)1911 f_scr_rvideo_mode(int page,int mode)
1912 {
1913 	int i, j, maxlines;
1914 
1915   if (rvideo != mode) {
1916 		rvideo = mode;
1917 		rstyle ^= RS_RVid;
1918 
1919 		maxlines = TermWin.vts[page].saveLines + TermWin.nrow;
1920 		for (i = TermWin.vts[page].saveLines; i < maxlines; i++)
1921 			for (j = 0; j < TermWin.vts[page].bcol + 1; j++)
1922 				screen[page].rend[i][j] ^= RS_RVid;
1923 		f_scr_refresh(page,SLOW_REFRESH);
1924 	}
1925 }
1926 
1927 /* ------------------------------------------------------------------------- */
1928 /*
1929  * Report current cursor position
1930  * XTERM_SEQ: Report position: ESC [ 6 n
1931  */
1932 
1933 
f_scr_report_position(int page)1934 void f_scr_report_position(int page)
1935 {
1936   tt_printf((unsigned char *)"\033[%d;%dR",
1937     screen[page].cur.row + 1, screen[page].cur.col + 1);
1938 }
1939 
1940 /* ------------------------------------------------------------------------- *
1941  *                                  FONTS                                    *
1942  * ------------------------------------------------------------------------- */
1943 
1944 /*
1945  * Set font style
1946  */
1947 
1948 
1949 
f_set_font_style(int page)1950 void f_set_font_style(int page)
1951 {
1952 	rstyle &= ~RS_fontMask;
1953 	switch (charsets[screen[page].charset])
1954 	{
1955 	case '0':		/* DEC Special Character & Line Drawing Set */
1956 		rstyle |= RS_acsFont;
1957 		break;
1958 	case 'A':		/* United Kingdom (UK) */
1959 		rstyle |= RS_ukFont;
1960 		break;
1961 	case 'B':		/* United States (USASCII) */
1962 		break;
1963 	case '<':		/* Multinational character set */
1964 		break;
1965 	case '5':		/* Finnish character set */
1966 		break;
1967 	case 'C':		/* Finnish character set */
1968 		break;
1969 	case 'K':		/* German character set */
1970 		break;
1971 	}
1972 }
1973 
1974 /* ------------------------------------------------------------------------- */
1975 /*
1976  * Choose a font
1977  * XTERM_SEQ: Invoke G0 character set: CTRL-O
1978  * XTERM_SEQ: Invoke G1 character set: CTRL-N
1979  * XTERM_SEQ: Invoke G2 character set: ESC N
1980  * XTERM_SEQ: Invoke G3 character set: ESC O
1981  */
1982 
f_scr_charset_choose(int page,int set)1983 void f_scr_charset_choose(int page,int set)
1984 {
1985 	screen[page].charset = set;
1986 	f_set_font_style(page);
1987 }
1988 
1989 
1990 /* ------------------------------------------------------------------------- */
1991 /*
1992  * Set a font
1993  * XTERM_SEQ: Set G0 character set: ESC ( <C>
1994  * XTERM_SEQ: Set G1 character set: ESC ) <C>
1995  * XTERM_SEQ: Set G2 character set: ESC * <C>
1996  * XTERM_SEQ: Set G3 character set: ESC + <C>
1997  * See set_font_style for possible values for <C>
1998  */
1999 
2000 
f_scr_charset_set(int page,int set,unsigned int ch)2001 void f_scr_charset_set(int page,int set, unsigned int ch)
2002 {
2003 #ifdef MULTICHAR_SET
2004 	multi_byte = (set < 0);
2005 	set = abs(set);
2006 #endif
2007 	charsets[set] = (unsigned char)ch;
2008 	f_set_font_style(page);
2009 }
2010 
2011 /* ------------------------------------------------------------------------- *
2012  *          MULTIPLE-CHARACTER FONT SET MANIPULATION FUNCTIONS               *
2013  * ------------------------------------------------------------------------- */
2014 #ifdef MULTICHAR_SET
2015 # ifdef KANJI
2016 static void     (*multichar_decode) (unsigned char *str, int len) = eucj2jis;
2017 # else				/* then we must be BIG5 to get in here */
2018 static void     (*multichar_decode) (unsigned char *str, int len) = big5dummy;
2019 # endif
2020 
eucj2jis(unsigned char * str,int len)2021 void eucj2jis(unsigned char *str, int len)
2022 {
2023 	register int    i;
2024 
2025 	for (i = 0; i < len; i++)
2026 		str[i] &= 0x7F;
2027 }
2028 
2029 /* ------------------------------------------------------------------------- */
sjis2jis(unsigned char * str,int len)2030 void sjis2jis(unsigned char *str, int len)
2031 {
2032 	register int    i;
2033 	unsigned char  *high, *low;
2034 
2035 	for (i = 0; i < len; i += 2, str += 2)
2036 	{
2037 		high = str;
2038 		low = str + 1;
2039 		(*high) -= (*high > 0x9F ? 0xB1 : 0x71);
2040 		*high = (*high) * 2 + 1;
2041 		if (*low > 0x9E)
2042 		{
2043 			*low -= 0x7E;
2044 			(*high)++;
2045 		} else
2046 		{
2047 			if (*low > 0x7E)
2048 				(*low)--;
2049 			*low -= 0x1F;
2050 		}
2051 	}
2052 }
2053 
big5dummy(unsigned char * str,int len)2054 void big5dummy(unsigned char *str, int len)
2055 {
2056 }
2057 
set_multichar_encoding(const char * str)2058 void set_multichar_encoding(const char *str)
2059 {
2060 	if (str && *str)
2061 	{
2062 		if (!strcmp(str, "sjis"))
2063 		{
2064 			encoding_method = SJIS;	/* Kanji SJIS */
2065 			multichar_decode = sjis2jis;
2066 		} else if (!strcmp(str, "eucj"))
2067 		{
2068 			encoding_method = EUCJ;	/* Kanji EUCJ */
2069 			multichar_decode = eucj2jis;
2070 		}
2071 	}
2072 }
2073 #endif				/* MULTICHAR_SET */
2074 
2075 /* ------------------------------------------------------------------------- *
2076  *                           GRAPHICS COLOURS                                *
2077  * ------------------------------------------------------------------------- */
2078 
2079 #ifdef RXVT_GRAPHICS
scr_get_fgcolor(void)2080 int scr_get_fgcolor(void)
2081 {
2082 	return GET_FGCOLOR(rstyle);
2083 }
2084 
2085 /* ------------------------------------------------------------------------- */
scr_get_bgcolor(void)2086 int scr_get_bgcolor(void)
2087 {
2088 	return GET_BGCOLOR(rstyle);
2089 }
2090 #endif
2091 
2092 /* ------------------------------------------------------------------------- *
2093  *                        MAJOR SCREEN MANIPULATION                          *
2094  * ------------------------------------------------------------------------- */
2095 
2096 /*
2097  * Refresh an area
2098  */
2099 
f_scr_expose(int page,int x,int y,int width,int height)2100 void f_scr_expose(int page,int x, int y, int width, int height)
2101 {
2102 	int             i;
2103 
2104 #if 0
2105 	text_t         *t;
2106 #endif
2107 	row_col_t       full_beg, full_end, part_beg, part_end;
2108 
2109 	if (drawn_text == NULL)	/* sanity check */
2110 		return;
2111 
2112 /* round down */
2113 	part_beg.col = Pixel2Col(x);
2114 	part_beg.row = Pixel2Row(y);
2115 	full_end.col = Pixel2Width(x + width);
2116 	full_end.row = Pixel2Row(y + height);
2117 
2118 /* round up */
2119 	part_end.col = Pixel2Width(x + width + TermWin.fwidth - 1);
2120 	part_end.row = Pixel2Row(y + height + TermWin.fheight - 1);
2121 	full_beg.col = Pixel2Col(x + TermWin.fwidth - 1);
2122 	full_beg.row = Pixel2Row(y + TermWin.fheight - 1);
2123 
2124 /* sanity checks */
2125 	MAX_IT(part_beg.col, 0);
2126 	MAX_IT(full_beg.col, 0);
2127 	MAX_IT(part_end.col, 0);
2128 	MAX_IT(full_end.col, 0);
2129 	MAX_IT(part_beg.row, 0);
2130 	MAX_IT(full_beg.row, 0);
2131 	MAX_IT(part_end.row, 0);
2132 	MAX_IT(full_end.row, 0);
2133 	MIN_IT(part_beg.col, TermWin.vts[page].bcol - 1);
2134 	MIN_IT(full_beg.col, TermWin.vts[page].bcol - 1);
2135 	MIN_IT(part_end.col, TermWin.vts[page].bcol - 1);
2136 	MIN_IT(full_end.col, TermWin.vts[page].bcol - 1);
2137 	MIN_IT(part_beg.row, TermWin.nrow - 1);
2138 	MIN_IT(full_beg.row, TermWin.nrow - 1);
2139 	MIN_IT(part_end.row, TermWin.nrow - 1);
2140 	MIN_IT(full_end.row, TermWin.nrow - 1);
2141 
2142 	DSCR_ALEXIS(1,(stderr,
2143 		  "scr_expose(x:%d, y:%d, w:%d, h:%d) area (c:%d,r:%d)-(c:%d,r:%d)\n",
2144 		  x, y, width, height, part_beg.col, part_beg.row,
2145 		  part_end.col, part_end.row));
2146 
2147 #if 1				/* XXX: check for backing store/save unders? */
2148 	for (i = part_beg.row; i <= part_end.row; i++)
2149 		MEMSET(&(drawn_text[i][part_beg.col]), 0,part_end.col - part_beg.col + 1);
2150 #else
2151 	if (full_end.col >= full_beg.col)
2152 	    /* set DEFAULT_RSTYLE for totally exposed characters */
2153 		for (i = full_beg.row; i <= full_end.row; i++)
2154 			blank_line(&(drawn_text[i][full_beg.col]),&(drawn_rend[i][full_beg.col]),
2155         full_end.col - full_beg.col + 1,DEFAULT_RSTYLE);
2156 /* force an update for partially exposed characters */
2157 	if (part_beg.row != full_beg.row)
2158 	{
2159 		t = &(drawn_text[part_beg.row][part_beg.col]);
2160 		for (i = part_end.col - part_beg.col + 1; i--;)
2161 			*t++ = 0;
2162 	}
2163 	if (part_end.row != full_end.row)
2164 	{
2165 		t = &(drawn_text[part_end.row][part_beg.col]);
2166 		for (i = part_end.col - part_beg.col + 1; i--;)
2167 			*t++ = 0;
2168 	}
2169 	if (part_beg.col != full_beg.col)
2170 		for (i = full_beg.row; i <= full_end.row; i++)
2171 			drawn_text[i][part_beg.col] = 0;
2172 	if (part_end.col != full_end.col)
2173 		for (i = full_beg.row; i <= full_end.row; i++)
2174 			drawn_text[i][part_end.col] = 0;
2175 #endif
2176 	f_scr_refresh(page,SLOW_REFRESH);
2177 }
2178 
2179 /* ------------------------------------------------------------------------- */
2180 /*
2181  * Refresh the entire screen
2182  */
2183 
f_scr_touch(int page)2184 void f_scr_touch(int page)
2185 {
2186 	f_scr_expose(page,0, 0, TermWin.width, TermWin.height);
2187 }
2188 
2189 /* ------------------------------------------------------------------------- */
2190 /*
2191  * Move the display so that the line represented by scrollbar value Y is at
2192  * the top of the screen
2193  */
f_scr_move_to(int page,int y,int len)2194 int f_scr_move_to(int page,int y, int len)
2195 {
2196 	int             start;
2197 
2198 	start = TermWin.vts[page].view_start;
2199 	TermWin.vts[page].view_start = ((len - y) * (TermWin.nrow - 1 + TermWin.vts[page].nscrolled) / (len)) -
2200     (TermWin.nrow - 1);
2201 	DSCR_ALEXIS(1,(stderr, "scr_move_to(%d, %d) view_start:%d\n", y, len,TermWin.vts[page].view_start));
2202 
2203 	MAX_IT(TermWin.vts[page].view_start, 0);
2204 	MIN_IT(TermWin.vts[page].view_start, TermWin.vts[page].nscrolled);
2205 
2206 	return (TermWin.vts[page].view_start - start);
2207 }
2208 
2209 /* ------------------------------------------------------------------------- */
2210 /*
2211  * Page the screen up/down nlines
2212  * direction  should be UP or DN
2213  */
f_scr_page(int page,int direction,int nlines)2214 int f_scr_page(int page,int direction, int nlines)
2215 {
2216 	int             start, dirn;
2217 
2218 	DSCR_ALEXIS(1,(stderr, "scr_page(%d,%s,%d) view_start:%d, nscrolled:%d\n",
2219     page,((direction == UP) ? "UP" : "DN"), nlines,
2220     TermWin.vts[page].view_start,TermWin.vts[page].nscrolled));
2221   DSCR_ALEXIS(1,(stderr,"scr_page(...) tscroll:%d, bscroll:%d\n",
2222     screen[page].tscroll,screen[page].bscroll));
2223 
2224 	dirn = (direction == UP) ? 1 : -1;
2225 	start = TermWin.vts[page].view_start;
2226   // on ne fait pas un deplacement inferieur a 1 ligne
2227 	MAX_IT(nlines, 1);
2228   // on ne fait pas un deplacement de plus de nrow
2229 	MIN_IT(nlines, TermWin.nrow);
2230 	TermWin.vts[page].view_start += (nlines * dirn);
2231 	MAX_IT(TermWin.vts[page].view_start, 0);
2232 	MIN_IT(TermWin.vts[page].view_start, TermWin.vts[page].nscrolled);
2233 
2234 	return (TermWin.vts[page].view_start - start);
2235 }
2236 
2237 /* ------------------------------------------------------------------------- */
2238 
scr_bell(void)2239 void scr_bell(void)
2240 {
2241 #ifndef NO_MAPALERT
2242 # ifdef MAPALERT_OPTION
2243 	if (Options & Opt_mapAlert)
2244 # endif
2245 		XMapWindow(Xdisplay, TermWin.parent);
2246 #endif
2247 	if (Options & Opt_visualBell)
2248 	{
2249 		f_scr_rvideo_mode(0,!rvideo);	/* scr_refresh() also done */
2250 		f_scr_rvideo_mode(0,!rvideo);	/* scr_refresh() also done */
2251 	} else
2252 		XBell(Xdisplay, 0);
2253 }
2254 
2255 /* ------------------------------------------------------------------------- */
2256 /* ARGSUSED */
f_scr_printscreen(int page,int fullhist)2257 void f_scr_printscreen(int page,int fullhist)
2258 {
2259 #ifdef PRINTPIPE
2260 	int             i, r, nrows, row_offset;
2261 	text_t         *t;
2262 	FILE           *fd;
2263 
2264 	if ((fd = popen_printer()) == NULL)
2265 		return;
2266 	nrows = TermWin.nrow;
2267 	if (fullhist)
2268 		nrows += TermWin.vts[page].view_start;
2269 
2270 	row_offset = TermWin.vts[page].saveLines - TermWin.vts[page].view_start;
2271 	for (r = 0; r < nrows; r++)
2272 	{
2273 		t = screen[page].text[r + row_offset];
2274 		for (i = TermWin.vts[page].bcol - 1; i >= 0; i--)
2275 			if (!isspace(t[i]))
2276 				break;
2277 		fprintf(fd, "%.*s\n", (i + 1), t);
2278 	}
2279 	pclose_printer(fd);
2280 #endif
2281 }
2282 
2283 /* ------------------------------------------------------------------------- */
2284 /*
2285  * Refresh the screen
2286  * drawn_text/drawn_rend contain the screen information before the update.
2287  * screen[0].text/screen[0].rend contain what the screen will change to.
2288  */
2289 
2290 /*#define DRAW_STRING(Func, x, y, str, len)				\
2291     Func(Xdisplay, drawBufferPage(0), TermWin.vts[0].gc, (x), (y), (str), (len))*/
2292 #define f_DRAW_STRING(page,Func, x, y, str, len)				\
2293     Func(Xdisplay, drawBufferPage(page), TermWin.vts[page].gc, (x), (y), (str), (len))
2294 
2295 #if defined (NO_BRIGHTCOLOR) || defined (VERYBOLD)
2296 # define MONO_BOLD(x)	((x) & (RS_Bold|RS_Blink))
2297 #else
2298 # define MONO_BOLD(x)	(((x) & RS_Bold) && fore == Color_fg)
2299 #endif
2300 
2301 
f_scr_refresh(int page,int type)2302 void f_scr_refresh(int page,int type)
2303 {
2304   int i, j,	/* tmp                                       */
2305       col, row,	/* column/row we're processing               */
2306       scrrow,	/* screen row offset                         */
2307       row_offset,	/* basic offset in screen structure          */
2308       currow,	/* cursor row at appropriate offset          */
2309       boldlast,	/* last character in some row was bold       */
2310       len, wlen,	/* text length screen/buffer                 */
2311       fprop,	/* proportional font used                    */
2312       is_cursor,	/* cursor this position                      */
2313       rvid,	/* reverse video this position               */
2314       rend,	/* rendition                                 */
2315       fore, back,	/* desired foreground/background             */
2316       wbyte,	/* we're in multibyte                        */
2317       morecur = 0, xpixel,	/* x offset for start of drawing (font)      */
2318       ypixel;	/* y offset for start of drawing (font)      */
2319 
2320   static int      focus = -1;	/* screen in focus?                          */
2321   long            gcmask;	/* Graphics Context mask                     */
2322   unsigned long   ltmp;
2323   rend_t          rt1, rt2;	/* tmp rend values                           */
2324 
2325 #ifndef NO_CURSORCOLOR
2326 	rend_t          ccol1,	/* Cursor colour                             */
2327 	                ccol2,	/* Cursor colour2                            */
2328 	                cc1;	/* store colours at cursor position(s)       */
2329 
2330 # ifdef MULTICHAR_SET
2331 	rend_t          cc2;	/* store colours at cursor position(s)       */
2332 # endif
2333 #endif
2334 	rend_t         *drp, *srp;	/* drawn-rend-pointer, screen-rend-pointer   */
2335 	text_t         *dtp, *stp;	/* drawn-text-pointer, screen-text-pointer   */
2336 	XGCValues       gcvalue;	/* Graphics Context values                   */
2337 	XFontStruct    *wf;	/* which font are we in                      */
2338 	static char    *buffer = NULL;
2339 	static int      currmaxcol = 0;
2340 
2341 #ifdef MULTICHAR_SET
2342 	static int      oldcursormulti = 0;
2343 #endif
2344 	static row_col_t oldcursor = { -1, -1 };
2345 
2346     /* is there an old outline cursor on screen? */
2347 
2348 #ifdef THAI			/* variables to clean un-touched space at the end of screen */
2349 	int             thaicol_stp_offset = 0;
2350 	int             thaicol_dtp_offset = 0;
2351 #endif
2352 
2353 #ifndef NO_BOLDFONT
2354 	int             bfont = 0;	/* we've changed font to bold font           */
2355 #endif
2356 	int             (*draw_string) (), (*draw_image_string) ();
2357 
2358 	if (type == NO_REFRESH)
2359 		return;
2360 
2361   DSCR_ALEXIS(2,(stderr,"f_scr_refresh(%d,...)\n",page));
2362 /*
2363  * A: set up vars
2364  */
2365 	if (currmaxcol < TermWin.ncol)
2366 	{
2367 		currmaxcol = TermWin.ncol;
2368 		if (buffer)
2369 			buffer =  REALLOC(buffer, (sizeof(char) * (currmaxcol + 1)));
2370 		else
2371 			buffer = MALLOC((sizeof(char) * (currmaxcol + 1)));
2372 	}
2373 	row_offset = TermWin.vts[page].saveLines - TermWin.vts[page].view_start;
2374 	fprop = TermWin.fprop;
2375 	is_cursor = 0;
2376 	gcvalue.foreground = PixColors[Color_fg];
2377 	gcvalue.background = PixColors[Color_bg];
2378 
2379 /*
2380  * always go back to the base font - it's much safer
2381  */
2382 	wbyte = 0;
2383   //assert(TermWin.vts[page].gc != None);
2384 	XSetFont(Xdisplay, TermWin.vts[page].gc, TermWin.font->fid);
2385 	draw_string = XDrawString;
2386 	draw_image_string = XDrawImageString;
2387 	boldlast = 0;
2388 
2389 #ifndef NO_BOLDOVERSTRIKE
2390 /*
2391  * B: Bold Overstrike pixel dropping avoidance.  Do this FIRST.
2392  *    Do a pass across each line at the start, require a refresh of anything
2393  *    that will need to be refreshed, due to pixels being dropped into our
2394  *    area by a previous character which has now been changed.
2395  */
2396 	for (row = 0; row < TermWin.nrow; row++)
2397 	{
2398 		scrrow = row + row_offset;
2399 		stp = screen[page].text[scrrow]; // on accede a la ligne
2400 		srp = screen[page].rend[scrrow]; // on accede au rendu de la ligne
2401 		dtp = drawn_text[row]; // on accede a la ligne qui sera affichee
2402 		drp = drawn_rend[row]; // on accede au rendu de la ligne a afficher
2403 # ifndef NO_BOLDFONT
2404 		if (TermWin.boldFont == NULL)
2405 		{
2406 # endif
2407 			wf = TermWin.font;
2408 			j = wbyte;
2409 			for (col = TermWin.ncol - 2; col >= 0; col--)
2410 			{
2411 				int             do_stuff;
2412 
2413 # if ! defined (NO_BRIGHTCOLOR) && ! defined (VERYBOLD)
2414 				fore = GET_FGCOLOR(drp[col]);
2415 # endif
2416 				if (!MONO_BOLD(drp[col]))
2417 					continue;
2418 				if (dtp[col] == stp[col] && drp[col] == srp[col])
2419 					continue;
2420 				if (wbyte)
2421 				{
2422 					;	/* TODO: handle multibyte */
2423 					continue;	/* don't go past here */
2424 				}
2425 				if (dtp[col] == ' ')
2426 				{	/* TODO: check character set? */
2427 					continue;
2428 				}
2429 
2430 				if (wf->per_char == NULL)
2431 					do_stuff = 1;
2432 				else if (dtp[col] >= wf->min_char_or_byte2 && dtp[col] < wf->max_char_or_byte2)
2433 				{
2434 					int char_num = dtp[col] - wf->min_char_or_byte2;
2435 					do_stuff = (wf->per_char[char_num].width == wf->per_char[char_num].rbearing);
2436 				} else
2437 					do_stuff = 0;
2438 
2439 				if (do_stuff)
2440 				{
2441 #ifndef THAI			/* this mess up Thai chars, we have to implement ourselves */
2442 					dtp[col + 1] = 0;
2443 #endif
2444 # if defined(MULTICHAR_SET) && ! defined(NO_BOLDOVERSTRIKE_MULTI)
2445 					if ((srp[col] & RS_multiMask) == RS_multi2)
2446 					{
2447 						col--;
2448 						wbyte = 1;
2449 						continue;
2450 					}
2451 # endif
2452 				}
2453 			}
2454 # if ! defined (NO_BRIGHTCOLOR) && ! defined (VERYBOLD)
2455 			fore = GET_FGCOLOR(srp[TermWin.ncol - 1]);
2456 # endif
2457 			if (MONO_BOLD(srp[TermWin.ncol - 1]))
2458 				boldlast = 1;
2459 			wbyte = j;
2460 # ifndef NO_BOLDFONT
2461 		}
2462 # endif
2463 	}
2464 #endif				/* ! NO_BOLDOVERSTRIKE */
2465 
2466 /*
2467  * C: reverse any characters which are selected
2468  */
2469 	f_scr_reverse_selection(page);
2470 
2471 /*
2472  * D: set the cursor character(s)
2473  */
2474 	currow = screen[page].cur.row + TermWin.vts[page].saveLines;
2475 	if (focus != TermWin.focus)
2476 		focus = TermWin.focus;
2477 	if (screen[page].flags & Screen_VisibleCursor && focus)
2478 	{
2479 		srp = &(screen[page].rend[currow][screen[page].cur.col]);
2480 #ifdef THAI
2481 		if (CharWidth(wf, screen[page].text[currow][screen[page].cur.col]) <= 0)
2482 			*srp ^= RS_Bold;
2483 #endif
2484 #ifndef NO_CURSORCOLOR
2485 		cc1 = *srp & (RS_fgMask | RS_bgMask);
2486 		if (Xdepth <= 2 || !rs_color[Color_cursor])
2487 			ccol1 = Color_fg;
2488 		else
2489 			ccol1 = Color_cursor;
2490 		if (Xdepth <= 2 || !rs_color[Color_cursor2])
2491 			ccol2 = Color_bg;
2492 		else
2493 			ccol2 = Color_cursor2;
2494 	    /*  changed by rev vide cursor patch */
2495 		*srp = SET_BGCOLOR(*srp, ccol1);
2496 		*srp = SET_FGCOLOR(*srp, ccol2);
2497 #endif
2498 #ifdef MULTICHAR_SET
2499 		rt1 = *srp & RS_multiMask;
2500 		if (rt1 == RS_multi1)
2501 		{
2502 			if (screen[page].cur.col < TermWin.vts[page].bcol - 2 && ((srp[1] & RS_multiMask) == RS_multi2))
2503 				morecur = 1;
2504 		} else if (rt1 == RS_multi2)
2505 		{
2506 			if (screen[page].cur.col > 0 && ((srp[-1] & RS_multiMask) == RS_multi1))
2507 				morecur = -1;
2508 		}
2509 		if (morecur)
2510 		{
2511 			srp += morecur;
2512 			*srp ^= RS_RVid;
2513 		}
2514 # ifndef NO_CURSORCOLOR
2515 		if (morecur)
2516 		{
2517 			cc2 = *srp & (RS_fgMask | RS_bgMask);
2518 			*srp = SET_BGCOLOR(*srp, ccol1);
2519 			*srp = SET_FGCOLOR(*srp, ccol2);
2520 		}
2521 # endif
2522 #endif
2523 	}
2524 	i = 0;
2525 	if (oldcursor.row != -1)
2526 	{
2527 	    /* make sure no outline cursor is left around */
2528 		if (screen[page].cur.row != oldcursor.row || screen[page].cur.col != oldcursor.col)
2529 		{
2530 			if (oldcursor.row < TermWin.nrow && oldcursor.col < TermWin.vts[page].bcol)
2531 			{
2532 				drawn_text[oldcursor.row][oldcursor.col] = 0;
2533 #ifdef MULTICHAR_SET
2534 				if (oldcursormulti)
2535 				{
2536 					col = oldcursor.col + oldcursormulti;
2537 					if (col < TermWin.ncol)
2538 						drawn_text[oldcursor.row][col] = 0;
2539 				}
2540 #endif
2541 			}
2542 			if (focus || !(screen[page].flags & Screen_VisibleCursor))
2543 				oldcursor.row = -1;
2544 			else
2545 				i = 1;
2546 		}
2547 	} else if (!focus)
2548 		i = 1;
2549 	if (i)
2550 	{
2551 		oldcursor.row = screen[page].cur.row;
2552 		oldcursor.col = screen[page].cur.col;
2553 #ifdef MULTICHAR_SET
2554 		oldcursormulti = morecur;
2555 #endif
2556 	}
2557 
2558 /*
2559  * E: OK, now the real pass
2560  */
2561 	for (row = 0; row < TermWin.nrow; row++)
2562 	{
2563 #ifdef THAI
2564 		char            thai_update[TermWin.ncol];	/* update map */
2565 		int             stpx, dtpx;
2566 
2567 	    /* compare drawn_text and screen[page].text and check which to update */
2568 		ThaiUpdateMap(screen[page].text[row + row_offset], drawn_text[row],
2569 			      screen[page].rend[row + row_offset], drawn_rend[row],
2570 			      thai_update, TermWin.ncol);
2571 
2572 /*
2573  * TODO: Change this algo to scalefont compatible
2574  */
2575 		thaicol_stp_offset = 0;	/* records how many column deficit */
2576 		thaicol_dtp_offset = TermWin.ncol - Thai_ColMaxPaint(dtp, TermWin.ncol);
2577 	    /* clean strings before redraw */
2578 		for (col = 0; col < TermWin.ncol; col++)
2579 		{
2580 			if (!ThaiIsMiddleLineCh(stp[col]))
2581 				thaicol_stp_offset++;
2582 		}
2583 
2584 		if (thaicol_stp_offset > thaicol_dtp_offset)
2585 		{
2586 			f_CLEAR_CHARS(page,Col2Pixel(TermWin.ncol - thaicol_stp_offset),
2587 				    ypixel - TermWin.font->ascent,
2588 				    thaicol_stp_offset);
2589 
2590 		}
2591 #endif
2592 		scrrow = row + row_offset;
2593 		stp = screen[page].text[scrrow];
2594 		srp = screen[page].rend[scrrow];
2595 		dtp = drawn_text[row];
2596 		drp = drawn_rend[row];
2597 		for (col = 0; col < TermWin.ncol; col++)
2598 		{
2599 		    /* compare new text with old - if exactly the same then continue */
2600 			rt1 = srp[col];	/* screen rendition */
2601 			rt2 = drp[col];	/* drawn rendition  */
2602 #ifdef THAI			/* updating conditional */
2603 			if (!thai_update[col])
2604 			{
2605 #else
2606 			if ((stp[col] == dtp[col])	/* must match characters to skip */
2607 			    && ((rt1 == rt2)	/* either rendition the same or  */
2608 				|| ((stp[col] == ' ')	/* space w/ no bg change */
2609 				    && (GET_BGATTR(rt1) == GET_BGATTR(rt2)))))
2610 			{
2611 #endif
2612 #ifdef MULTICHAR_SET
2613 			    /* if first byte is Kanji then compare second bytes */
2614 				if ((rt1 & RS_multiMask) != RS_multi1)
2615 					continue;
2616 				else if (stp[col + 1] == dtp[col + 1])
2617 				{
2618 				    /* assume no corrupt characters on the screen */
2619 					col++;
2620 					continue;
2621 				}
2622 #else
2623 				continue;
2624 #endif
2625 			}
2626 		    /* redraw one or more characters */
2627 #ifndef THAI			/* can not set dtp as we go because it causes
2628 				 * unpredictable results (bug)
2629 				 */
2630 			dtp[col] = stp[col];
2631 #endif
2632 			rend = drp[col] = srp[col];
2633 
2634 			len = 0;
2635 			buffer[len++] = stp[col];
2636 			ypixel = TermWin.font->ascent + Row2Pixel(row);
2637 #ifdef THAI			/* compute x coordinate */
2638 			xpixel = ThaiCol2Pixel(col, screen[page].text[scrrow]);
2639 #else
2640 			xpixel = Col2Pixel(col);
2641 #endif				/* THAI */
2642 			wlen = 1;
2643 
2644 /*
2645  * Find out the longest string we can write out at once
2646  */
2647 			if (fprop == 0)
2648 			{	/* Fixed width font */
2649 #ifdef MULTICHAR_SET
2650 				if (((rend & RS_multiMask) == RS_multi1)
2651 				    && col < TermWin.ncol - 1
2652 				    && ((srp[col + 1]) & RS_multiMask) ==  RS_multi2)
2653 				{
2654 					if (!wbyte)
2655 					{
2656 						wbyte = 1;
2657 						XSetFont(Xdisplay, TermWin.vts[page].gc,TermWin.mfont->fid);
2658 						draw_string = XDrawString16;
2659 						draw_image_string = XDrawImageString16;
2660 					}
2661 				    /* double stepping - we're in Kanji mode */
2662 					for (; ++col < TermWin.vts[page].bcol;)
2663 					{
2664 					    /* XXX: could check sanity on 2nd byte */
2665 						dtp[col] = stp[col];
2666 						drp[col] = srp[col];
2667 						buffer[len++] = stp[col];
2668 						col++;
2669 						if ((col == TermWin.vts[page].bcol)
2670 						    || (srp[col] != rend))
2671 							break;
2672 						if ((stp[col] == dtp[col])
2673 						    && (srp[col] == drp[col])
2674 						    && (stp[col + 1] ==	dtp[col + 1]))
2675 							break;
2676 						if (len == currmaxcol)
2677 							break;
2678 						dtp[col] = stp[col];
2679 						drp[col] = srp[col];
2680 						buffer[len++] = stp[col];
2681 					}
2682 					col--;
2683 					if (buffer[0] & 0x80)
2684 						multichar_decode(buffer, len);
2685 					wlen = len / 2;
2686 				} else
2687 				{
2688 					if ((rend & RS_multiMask) == RS_multi1)
2689 					{
2690 					    /* XXX : maybe do the same thing for RS_multi2 */
2691 					    /* corrupt character - you're outta there */
2692 						rend &= ~RS_multiMask;
2693 						drp[col] = rend;	/* TODO check: may also want */
2694 						dtp[col] = ' ';	/* to poke into stp/srp      */
2695 						buffer[0] = ' ';
2696 					}
2697 					if (wbyte)
2698 					{
2699 						wbyte = 0;
2700 						XSetFont(Xdisplay, TermWin.vts[page].gc,TermWin.font->fid);
2701 						draw_string = XDrawString;
2702 						draw_image_string = XDrawImageString;
2703 					}
2704 #endif
2705 				    /* single stepping - `normal' mode */
2706 					for (; ++col < TermWin.ncol - 1;)
2707 					{
2708 						if (rend != srp[col])
2709 							break;
2710 						if ((stp[col] == dtp[col]) && (srp[col] == drp[col]))
2711 							break;
2712 						if (len == currmaxcol)
2713 							break;
2714 						dtp[col] = stp[col];
2715 						drp[col] = srp[col];
2716 						buffer[len++] = stp[col];
2717 					}
2718 					col--;
2719 					wlen = len;
2720 #ifdef MULTICHAR_SET
2721 				}
2722 #endif
2723 			}
2724 			buffer[len] = '\0';
2725 
2726 /*
2727  * Determine the attributes for the string
2728  */
2729 			fore = GET_FGCOLOR(rend);
2730 			back = GET_BGCOLOR(rend);
2731 			rend = GET_ATTR(rend);
2732 			gcmask = 0;
2733 			rvid = (rend & RS_RVid) ? 1 : 0;
2734 
2735 			switch (rend & RS_fontMask)
2736 			{
2737 			case RS_acsFont:
2738 				for (i = 0; i < len; i++)
2739 					if (buffer[i] == 0x5f)
2740 						buffer[i] = 0x7f;
2741 					else if (buffer[i] > 0x5f
2742 						 && buffer[i] < 0x7f)
2743 						buffer[i] -= 0x5f;
2744 				break;
2745 			case RS_ukFont:
2746 				for (i = 0; i < len; i++)
2747 					if (buffer[i] == '#')
2748 						buffer[i] = 0x1e;
2749 				break;
2750 			}
2751 			if (rvid)
2752 				SWAP_IT(fore, back, i);
2753 
2754 			if (colors_changed)
2755 			{
2756 				gcvalue.background = PixColors[back];
2757 				gcmask |= GCBackground;
2758 				gcvalue.foreground = PixColors[fore];
2759 				gcmask |= GCForeground;
2760 				colors_changed = 0;
2761 			} else if (back != Color_bg)
2762 			{
2763 				gcvalue.background = PixColors[back];
2764 				gcmask |= GCBackground;
2765 			}
2766 			if (fore != Color_fg)
2767 			{
2768 				gcvalue.foreground = PixColors[fore];
2769 				gcmask |= GCForeground;
2770 			}
2771 #ifndef NO_BOLDUNDERLINE
2772 			else if (rend & RS_Bold)
2773 			{
2774 				if (Xdepth > 2 && rs_color[Color_BD]
2775 				    && PixColors[fore] != PixColors[Color_BD]
2776 				    && PixColors[back] != PixColors[Color_BD])
2777 				{
2778 					gcvalue.foreground = PixColors[Color_BD];
2779 					gcmask |= GCForeground;
2780 # ifndef VERYBOLD
2781 					rend &= ~RS_Bold;	/* we've taken care of it */
2782 # endif
2783 				}
2784 			} else if (rend & RS_Uline)
2785 			{
2786 				if (Xdepth > 2 && rs_color[Color_UL]
2787 				    && PixColors[fore] != PixColors[Color_UL]
2788 				    && PixColors[back] != PixColors[Color_UL])
2789 				{
2790 					gcvalue.foreground = PixColors[Color_UL];
2791 					gcmask |= GCForeground;
2792 					rend &= ~RS_Uline;	/* we've taken care of it */
2793 				}
2794 			}
2795 #endif
2796 
2797 			if (gcmask)
2798 				XChangeGC(Xdisplay, TermWin.vts[page].gc, gcmask,&gcvalue);
2799 
2800 #ifndef NO_BOLDFONT
2801 			if (!wbyte && MONO_BOLD(rend)
2802 			    && TermWin.boldFont != NULL)
2803 			{
2804 				bfont = 1;
2805 				XSetFont(Xdisplay, TermWin.vts[page].gc,TermWin.boldFont->fid);
2806 				rend &= ~RS_Bold;	/* we've taken care of it */
2807 			} else if (bfont)
2808 			{
2809 				bfont = 0;
2810 				XSetFont(Xdisplay, TermWin.vts[page].gc,TermWin.font->fid);
2811 			}
2812 #endif
2813 /*
2814  * Actually do the drawing of the string here
2815  */
2816 			if (fprop)
2817 			{
2818 #ifdef THAI
2819 				if (rvid && CharWidth(wf, stp[col]) > 0)
2820 				{
2821 #else
2822 				if (rvid)
2823 				{
2824 #endif
2825 					SWAP_IT(gcvalue.foreground,gcvalue.background, ltmp);
2826 					gcmask |= (GCForeground | GCBackground);
2827 					XChangeGC(Xdisplay, TermWin.vts[page].gc, gcmask,&gcvalue);
2828 					XFillRectangle(Xdisplay, drawBufferPage(page),
2829 						       TermWin.vts[page].gc, xpixel,
2830 						       ypixel - TermWin.font->ascent,
2831 						       Width2Pixel(1),
2832 						       Height2Pixel(1));
2833 					SWAP_IT(gcvalue.foreground,gcvalue.background, ltmp);
2834 					XChangeGC(Xdisplay, TermWin.vts[page].gc, gcmask, &gcvalue);
2835 				} else
2836 #ifdef THAI
2837 				if (CharWidth(wf, stp[col]) > 0)
2838 #endif
2839         f_CLEAR_CHARS(page,xpixel, ypixel - TermWin.font->ascent, 1);
2840 				f_DRAW_STRING(page,draw_string, xpixel, ypixel,buffer, 1);
2841 #ifdef THAI
2842 /*
2843  * Trap error
2844  */
2845 				if (wlen > 1)
2846 					DSCR_ALEXIS(2,(stderr, "wlen > 1: %d\n",wlen));
2847 #endif
2848 #ifndef NO_BOLDOVERSTRIKE
2849 				if (MONO_BOLD(rend))
2850 					f_DRAW_STRING(page,draw_string, xpixel + 1, ypixel, buffer, 1);
2851 #endif
2852 			} else
2853 #ifdef TRANSPARENT
2854 			if ((Options & Opt_transparent) && back == Color_bg)
2855       //if((Options & TermWin.vts[page].bg.transparent) && back == Color_bg)
2856 			{
2857 #ifdef THAI
2858 				if (CharWidth(wf, stp[col]) > 0)
2859 #endif
2860 					f_CLEAR_CHARS(page,xpixel,ypixel - TermWin.font->ascent, len);
2861 				f_DRAW_STRING(page,draw_string, xpixel, ypixel, buffer, wlen);
2862 			} else
2863 #endif
2864 #if defined(BACKGROUND_IMAGE) || defined(_MYSTYLE_)
2865 			if (TermWin.vts[page].bg.trgPixmapSet && back == Color_bg)
2866 			{
2867 				f_CLEAR_CHARS(page,xpixel,ypixel - TermWin.font->ascent,len);
2868 				f_DRAW_STRING(page,draw_string, xpixel, ypixel,buffer, wlen);
2869 			} else
2870 #endif
2871 				f_DRAW_STRING(page,draw_image_string, xpixel, ypixel,buffer, wlen);
2872 
2873 #ifndef NO_BOLDOVERSTRIKE
2874 # ifdef NO_BOLDOVERSTRIKE_MULTI
2875 			if (!wbyte)
2876 # endif
2877 				if (MONO_BOLD(rend))
2878 					f_DRAW_STRING(page,draw_string, xpixel + 1,ypixel, buffer, wlen);
2879 #endif
2880 			if ((rend & RS_Uline) && (TermWin.font->descent > 1))
2881 				XDrawLine(Xdisplay, drawBufferPage(page), TermWin.vts[page].gc,
2882 					  xpixel, ypixel + 1,
2883 					  xpixel + Width2Pixel(len) - 1,
2884 					  ypixel + 1);
2885 			if (gcmask)
2886 			{	/* restore normal colours */
2887 				gcvalue.foreground = PixColors[Color_fg];
2888 				gcvalue.background = PixColors[Color_bg];
2889 				XChangeGC(Xdisplay, TermWin.vts[page].gc, gcmask,&gcvalue);
2890 			}
2891 		}
2892 	}
2893 #ifdef THAI
2894 /*
2895  * Hack: update drawn_text
2896  */
2897 	for (row = 0; row < TermWin.nrow; row++)
2898 	{
2899 		scrrow = row + row_offset;
2900 		stp = screen[page].text[scrrow];
2901 		srp = screen[page].rend[scrrow];
2902 		dtp = drawn_text[row];
2903 		drp = drawn_rend[row];
2904 
2905 		for (col = 0; col < TermWin.ncol; col++)
2906 		{
2907 			dtp[col] = stp[col];
2908 			drp[col] = srp[col];
2909 		}
2910 	}
2911 #endif
2912 
2913 /*
2914  * F: cleanup cursor and display outline cursor in necessary
2915  */
2916 	if (screen[page].flags & Screen_VisibleCursor)
2917 	{
2918 		if (focus)
2919 		{
2920 			srp = &(screen[page].rend[currow][screen[page].cur.col]);
2921 #ifdef THAI
2922 			if (CharWidth(wf, screen[page].text[currow][screen[page].cur.col]) <= 0)
2923 				*srp ^= RS_Bold;
2924 #endif
2925 #ifndef NO_CURSORCOLOR
2926 			*srp = (*srp & ~(RS_fgMask | RS_bgMask)) | cc1;
2927 #endif
2928 			if (morecur)
2929 			{
2930 				srp += morecur;
2931 #if defined(MULTICHAR_SET) && ! defined(NO_CURSORCOLOR)
2932 				*srp = (*srp & ~(RS_fgMask | RS_bgMask)) | cc2;
2933 #endif
2934 			}
2935 		} else
2936 		{
2937 			currow = screen[page].cur.row - TermWin.vts[page].view_start;
2938 			col = screen[page].cur.col + morecur;
2939 			wbyte = morecur ? 1 : 0;
2940 			if (currow >= 0 && currow < TermWin.nrow)
2941 			{
2942 #ifndef NO_CURSORCOLOR
2943 				gcmask = 0;
2944 				if (Xdepth > 2 && rs_color[Color_cursor])
2945 				{
2946 					gcvalue.foreground = PixColors[Color_cursor];
2947 					gcmask = GCForeground;
2948 					XChangeGC(Xdisplay, TermWin.vts[page].gc, gcmask, &gcvalue);
2949 					gcvalue.foreground = PixColors[Color_fg];
2950 				}
2951 #endif
2952 #ifdef THAI
2953         XDrawRectangle(Xdisplay, drawBufferPage(page),
2954           TermWin.vts[page].gc,
2955           ThaiCol2Pixel(col,screen[page].text[screen[page].cur.row + TermWin.vts[page].saveLines]),
2956           Row2Pixel(currow),
2957           Width2Pixel(1 + wbyte) - 1,
2958           Height2Pixel(1) - 1);
2959 
2960 #else
2961 
2962 				XDrawRectangle(Xdisplay, drawBufferPage(page),
2963           TermWin.vts[page].gc, Col2Pixel(col),
2964           Row2Pixel(currow),
2965           Width2Pixel(1 + wbyte) - 1,
2966           Height2Pixel(1) - 1);
2967 #endif
2968 #ifndef NO_CURSORCOLOR
2969 				if (gcmask)	/* restore normal colours */
2970 					XChangeGC(Xdisplay, TermWin.vts[page].gc, gcmask,&gcvalue);
2971 #endif
2972 			}
2973 		}
2974 	}
2975 
2976 /*
2977  * G: cleanup selection
2978  */
2979 	f_scr_reverse_selection(page);
2980 
2981 /*
2982  * H: other general cleanup
2983  */
2984  DSCR_ALEXIS(2,(stderr,"vt[%d] is %s\n",page,TermWin.vts[page].bMapped ? "mapped" : "unmapped"));
2985 	if (boldlast && TermWin.vts[page].bMapped)	/* clear the whole screen height */
2986 		XClearArea(Xdisplay, TermWin.vts[page].vt, TermWin_TotalWidth() - 2, 0,
2987 			   1, TermWin_TotalHeight() - 1, 0);
2988 	if (type & SMOOTH_REFRESH)
2989 		XSync(Xdisplay, False);
2990 }
2991 
2992 
2993 
2994 void f_scr_clear_tint(int page,int bWithTinting)
2995 {
2996 	if (!TermWin.vts[page].bMapped)
2997 		return;
2998   DSCR_ALEXIS(2,(stderr,"f_scr_clear_tint(%d,%d)\n",page,bWithTinting));
2999 #ifdef TRANSPARENT
3000 	if (Options & Opt_transparent)
3001   //if (Options & TermWin.vts[page].bg.transparent)
3002 	{
3003 /*	int n ;
3004 	fprintf( stderr, "\n Clearing Parents ...");
3005 	for( n = 0 ; n < ParentWinNum ; n++ )
3006 */
3007 		XClearWindow(Xdisplay, TermWin.parent);
3008 /*	XFlush( Xdisplay );
3009 	sleep(5);
3010 	fprintf( stderr, "Done.");
3011 */ }
3012 #endif
3013 	XClearWindow(Xdisplay, TermWin.vts[page].vt);
3014 
3015 #if defined(BACKGROUND_IMAGE) || defined(TRANSPARENT)
3016 	if (TermWin.vts[page].tintGC && bWithTinting)
3017 	{
3018 		XFillRectangle(Xdisplay, TermWin.vts[page].vt, TermWin.vts[page].tintGC, 0, 0,
3019 			       TermWin.width + TermWin_internalBorders,
3020 			       TermWin.height + TermWin_internalBorders);
3021 	}
3022 #endif
3023 }
3024 
3025 /* ------------------------------------------------------------------------- */
3026 /* colors has changed so we have to repaint self			     */
3027 void f_on_colors_changed(int page,int idx)
3028 {
3029 	colors_changed = 1;
3030 	if (idx == Color_bg && !(Options & Opt_transparent))
3031   //if (idx == Color_bg && ! (Options & TermWin.vts[page].bg.transparent))
3032 	{
3033 		XSetWindowBackground(Xdisplay, TermWin.vts[page].vt,PixColors[Color_bg]);
3034 	}
3035 
3036 /* handle Color_BD, scrollbar background, etc. */
3037 
3038 	set_colorfgbg();
3039 	set_cursor_color();
3040 /* the only reasonable way to enforce a clean update : */
3041 	f_scr_clear(page);
3042 	f_scr_touch(page);
3043 }
3044 
3045 
3046 /* ------------------------------------------------------------------------- */
3047 /* PROTO */
3048 void
3049 f_scr_reverse_selection(int page)
3050 {
3051 	int             i, col, row, end_row;
3052 	rend_t         *srp;
3053 
3054   DSEL_ALEXIS(2,(stderr,"f_scr_reverse_selection(%d)\n",page));
3055 	end_row = TermWin.vts[page].saveLines - TermWin.vts[page].view_start;
3056 	if (selection.op /*&& current_screen == selection.screen*/ && selection.vt == page)
3057 	{
3058 		i = selection.beg.row + TermWin.vts[page].saveLines;
3059 		row = selection.end.row + TermWin.vts[page].saveLines;
3060 		if (i >= end_row)
3061 			col = selection.beg.col;
3062 		else
3063 		{
3064 			col = 0;
3065 			i = end_row;
3066 		}
3067 		end_row += TermWin.nrow;
3068 		for (; i < row && i < end_row; i++, col = 0)
3069 			for (srp = screen[page].rend[i]; col < TermWin.vts[page].bcol; col++)
3070 				srp[col] ^= RS_RVid;
3071 		if (i == row && i < end_row)
3072 			for (srp = screen[page].rend[i]; col < selection.end.col; col++)
3073 				srp[col] ^= RS_RVid;
3074 	}
3075 
3076 }
3077 
3078 /* ------------------------------------------------------------------------- *
3079  *                           CHARACTER SELECTION                             *
3080  * ------------------------------------------------------------------------- */
3081 
3082 /*
3083  * -TermWin.nscrolled <= (selection row) <= TermWin.nrow - 1
3084  */
3085 /* PROTO */
3086 void
3087 f_selection_check(int page,int check_more)
3088 {
3089 	row_col_t       pos;
3090 
3091   DSEL_ALEXIS(2,(stderr,"f_selection_check(%d,%d)\n",page,check_more));
3092 	if ((selection.beg.row < -TermWin.vts[page].nscrolled)
3093 	    || (selection.beg.row >= TermWin.nrow)
3094 	    || (selection.mark.row < -TermWin.vts[page].nscrolled)
3095 	    || (selection.mark.row >= TermWin.nrow)
3096 	    || (selection.end.row < -TermWin.vts[page].nscrolled)
3097 	    || (selection.end.row >= TermWin.nrow))
3098 		CLEAR_ALL_SELECTION;
3099 
3100 	if (check_more == 1 && current_screen == selection.screen)
3101 	{
3102 	    /* check for cursor position */
3103 		pos.row = screen[page].cur.row;
3104 		pos.col = screen[page].cur.col;
3105 		if (!ROWCOL_IS_BEFORE(pos, selection.beg)
3106 		    && ROWCOL_IS_BEFORE(pos, selection.end))
3107 			CLEAR_SELECTION;
3108 	} else if (check_more == 2)
3109 	{
3110 		pos.row = 0;
3111 		pos.col = 0;
3112 		if (ROWCOL_IS_BEFORE(selection.beg, pos)
3113 		    && ROWCOL_IS_AFTER(selection.end, pos))
3114 			CLEAR_SELECTION;
3115 	} else if (check_more == 3)
3116 	{
3117 		pos.row = 0;
3118 		pos.col = 0;
3119 		if (ROWCOL_IS_AFTER(selection.end, pos))
3120 			CLEAR_SELECTION;
3121 	}
3122 }
3123 
3124 /* ------------------------------------------------------------------------- */
3125 /*
3126  * Paste a selection direct to the command
3127  */
3128 /* PROTO */
3129 void
3130 f_PasteIt(int page,unsigned char *data, unsigned int nitems)
3131 {
3132 	int             num;
3133 	unsigned char  *p, cr;
3134 
3135   DSEL_ALEXIS(2,(stderr,"f_PasteIt(%d)\n",page));
3136 
3137 	cr = '\r';
3138 	for (p = data, num = 0; nitems--; p++)
3139 		if (*p != '\n')
3140 			num++;
3141 		else
3142 		{
3143 			f_tt_write(page,data, num);
3144 			f_tt_write(page,&cr, 1);
3145 			data += (num + 1);
3146 			num = 0;
3147 		}
3148 	if (num)
3149 		f_tt_write(page,data, num);
3150 }
3151 
3152 /* ------------------------------------------------------------------------- */
3153 /*
3154  * Respond to a notification that a primary selection has been sent
3155  * EXT: SelectionNotify
3156  */
3157 /* PROTO */
3158 void
3159 selection_paste(Window win, unsigned prop, int Delete)
3160 {
3161 	long            nread;
3162 	unsigned long   bytes_after, nitems;
3163 	unsigned char  *data;
3164 	Atom            actual_type;
3165 	int             actual_fmt;
3166 
3167   DSEL_ALEXIS(2,(stderr,"selection_paste(...)\n"));
3168 	if (prop == None)
3169 		return;
3170 	for (nread = 0, bytes_after = 1; bytes_after > 0; nread += nitems)
3171 	{
3172 		if ((XGetWindowProperty
3173 		     (Xdisplay, win, prop, (nread / 4), PROP_SIZE, Delete,
3174 		      AnyPropertyType, &actual_type, &actual_fmt, &nitems,
3175 		      &bytes_after, &data) != Success))
3176 		{
3177 			XFree(data);
3178 			return;
3179 		}
3180 		f_PasteIt(TermWin.active_page,data, nitems);
3181 		XFree(data);
3182 	}
3183 }
3184 
3185 /* ------------------------------------------------------------------------- */
3186 /*
3187  * Request the current primary selection
3188  * EXT: button 2 release
3189  */
3190 void f_selection_request(int page,Time tm, int x, int y)
3191 {
3192 	Atom            prop;
3193   DSEL_ALEXIS(2,(stderr,"f_selection_request(%d)\n",page));
3194 
3195 	if (x < 0 || x >= TermWin.width || y < 0 || y >= TermWin.height)
3196 		return;		/* outside window */
3197 
3198 	if (selection.text != NULL)
3199 	{
3200 		f_PasteIt(TermWin.active_page,selection.text, selection.len);	/* internal selection */
3201 	} else if (XGetSelectionOwner(Xdisplay, XA_PRIMARY) == None)
3202 	{
3203 		selection_paste(Xroot, XA_CUT_BUFFER0, False);
3204 	} else
3205 	{
3206 		prop = XInternAtom(Xdisplay, "VT_SELECTION", False);
3207 		XConvertSelection(Xdisplay, XA_PRIMARY, XA_STRING, prop,
3208 				  TermWin.vts[page].vt, tm);
3209 	}
3210 }
3211 
3212 /* ------------------------------------------------------------------------- */
3213 /*
3214  * Clear all selected text
3215  * EXT: SelectionClear
3216  */
3217 void selection_clear(void)
3218 {
3219 	//D_SELECT((stderr, "selection_clear()"));
3220 
3221   DSEL_ALEXIS(2,(stderr,"selection_clear()\n"));
3222 
3223 	if (selection.text)
3224 		FREE(selection.text);
3225 	selection.text = NULL;
3226 	selection.len = 0;
3227 	CLEAR_SELECTION;
3228   selection.vt = -1;
3229 }
3230 
3231 /* ------------------------------------------------------------------------- */
3232 /*
3233  * Copy a selection into the cut buffer
3234  * EXT: button 1 or 3 release
3235  */
3236 
3237 void f_selection_make(int page,Time tm)
3238 {
3239 	int             i, col, end_col, row, end_row;
3240 	unsigned char  *new_selection_text;
3241 	char           *str;
3242 	text_t         *t;
3243 
3244 	DSEL_ALEXIS(2,(stderr,
3245 		  "selection_make(): selection.op=%d, selection.clicks=%d\n",
3246 		  selection.op, selection.clicks));
3247 	switch (selection.op)
3248 	{
3249 	case SELECTION_CONT:
3250 		break;
3251 	case SELECTION_INIT:
3252 		CLEAR_SELECTION;
3253 	    /* FALLTHROUGH */
3254 	case SELECTION_BEGIN:
3255 		selection.op = SELECTION_DONE;
3256 	    /* FALLTHROUGH */
3257 	default:
3258 		return;
3259 	}
3260 	selection.op = SELECTION_DONE;
3261   selection.vt = page;
3262 
3263 	if (selection.clicks == 4)
3264 		return;		/* nothing selected, go away */
3265 
3266 	i = (selection.end.row - selection.beg.row + 1) * (TermWin.vts[page].bcol + 1) +
3267 	    1;
3268 	str = MALLOC(i * sizeof(char));
3269 	new_selection_text = (unsigned char *)str;
3270 
3271 	col = max(selection.beg.col, 0);
3272 	row = selection.beg.row + TermWin.vts[page].saveLines;
3273 	end_row = selection.end.row + TermWin.vts[page].saveLines;
3274 /*
3275  * A: rows before end row
3276  */
3277 	for (; row < end_row; row++)
3278 	{
3279 		t = &(screen[page].text[row][col]);
3280 		if ((end_col = screen[page].tlen[row]) == -1)
3281 			end_col = TermWin.vts[page].bcol;
3282 		for (; col < end_col; col++)
3283 			*str++ = *t++;
3284 		col = 0;
3285 		if (screen[page].tlen[row] != -1)
3286 			*str++ = '\n';
3287 	}
3288 /*
3289  * B: end row
3290  */
3291 	t = &(screen[page].text[row][col]);
3292 	end_col = screen[page].tlen[row];
3293 	if (end_col == -1 || selection.end.col <= end_col)
3294 		end_col = selection.end.col;
3295 	MIN_IT(end_col, TermWin.vts[page].bcol);	/* CHANGE */
3296 	for (; col < end_col; col++)
3297 		*str++ = *t++;
3298 	if (end_col != selection.end.col)
3299 		*str++ = '\n';
3300 	*str = '\0';
3301 	if ((i = strlen((char *)new_selection_text)) == 0)
3302 	{
3303 		FREE(new_selection_text);
3304 		return;
3305 	}
3306 	selection.len = i;
3307 
3308 	if (selection.text)
3309 		FREE(selection.text);
3310 
3311 	selection.text = new_selection_text;
3312 
3313 	XSetSelectionOwner(Xdisplay, XA_PRIMARY, TermWin.vts[page].vt, tm);
3314 
3315 	if (XGetSelectionOwner(Xdisplay, XA_PRIMARY) != TermWin.vts[page].vt)
3316 		print_error("can't get primary selection");
3317 
3318 	XChangeProperty(Xdisplay, Xroot, XA_CUT_BUFFER0, XA_STRING, 8,
3319 			PropModeReplace, selection.text, selection.len);
3320 	DSEL_ALEXIS(2,(stderr, "selection_make(): selection.len=%d\n", selection.len));
3321 }
3322 
3323 /* ------------------------------------------------------------------------- */
3324 /*
3325  * Mark or select text based upon number of clicks: 1, 2, or 3
3326  * EXT: button 1 press
3327  */
3328 /* PROTO */
3329 void
3330 selection_click(int clicks, int x, int y)
3331 {
3332 /*    int             r, c;
3333  *   row_col_t             ext_beg, ext_end;
3334  */
3335 
3336 	DSEL_ALEXIS(2,(stderr, "selection_click(%d, %d, %d)\n", clicks, x, y));
3337   selection.vt = TermWin.active_page;
3338 
3339 	clicks = ((clicks - 1) % 3) + 1;
3340 	selection.clicks = clicks;	/* save clicks so extend will work */
3341 #ifdef THAI
3342 	selection_start_colrow(ThaiPixel2Col(x, y), Pixel2Row(y));
3343 #else
3344 	selection_start_colrow(Pixel2Col(x), Pixel2Row(y));
3345 #endif
3346 	if (clicks == 2 || clicks == 3)
3347 		f_selection_extend_colrow(TermWin.active_page,selection.mark.col,
3348       selection.mark.row + TermWin.vts[TermWin.active_page].view_start,
3349       0,	/* button 3     */
3350 			1,	/* button press */
3351 			0);	/* click change */
3352 }
3353 
3354 /* ------------------------------------------------------------------------- */
3355 /*
3356  * Mark a selection at the specified col/row
3357  */
3358 
3359 void selection_start_colrow(int col, int row)
3360 {
3361   DSEL_ALEXIS(2,(stderr, "selection_start_colrow(%d, %d)\n",col,row));
3362   selection.vt = TermWin.active_page;
3363 	selection.mark.col = col;
3364 	selection.mark.row = row - TermWin.vts[TermWin.active_page].view_start;
3365 	MAX_IT(selection.mark.row, -TermWin.vts[TermWin.active_page].nscrolled);
3366 	MIN_IT(selection.mark.row, TermWin.nrow - 1);
3367 	MAX_IT(selection.mark.col, 0);
3368 	MIN_IT(selection.mark.col, TermWin.vts[TermWin.active_page].bcol - 1);
3369 
3370 	if (selection.op)
3371 	{			/* clear the old selection */
3372 		selection.beg.row = selection.end.row = selection.mark.row;
3373 		selection.beg.col = selection.end.col = selection.mark.col;
3374 	}
3375 	selection.op = SELECTION_INIT;
3376 	selection.screen = current_screen;
3377 }
3378 
3379 /* ------------------------------------------------------------------------- */
3380 /*
3381  * Word select: select text for 2 clicks
3382  * We now only find out the boundary in one direction
3383  */
3384 
3385 /* what do we want: spaces/tabs are delimiters or cutchars or non-cutchars */
3386 #define DELIMIT_TEXT(x) \
3387     (((x) == ' ' || (x) == '\t') ? 2 : (strchr(rs_cutchars, (x)) != NULL))
3388 #ifdef MULTICHAR_SET
3389 # define DELIMIT_REND(x)	(((x) & RS_multiMask) ? 1 : 0)
3390 #else
3391 # define DELIMIT_REND(x)	1
3392 #endif
3393 
3394 void f_selection_delimit_word(int page,int dirn, row_col_t * mark, row_col_t * ret)
3395 {
3396 	int             col, row, dirnadd, tcol, trow, w1, w2;
3397 	row_col_t       bound;
3398 	text_t         *stp;
3399 	rend_t         *srp;
3400 
3401   DSEL_ALEXIS(2,(stderr, "f_selection_delimit_word(%d, %d)\n",page,dirn));
3402   selection.vt = TermWin.active_page;
3403 	if (selection.clicks != 2)
3404 		return;		/* Go away: we only handle double clicks */
3405 
3406 	if (dirn == UP)
3407 	{
3408 		bound.row = TermWin.vts[page].saveLines - TermWin.vts[page].nscrolled - 1;
3409 		bound.col = 0;
3410 		dirnadd = -1;
3411 	} else
3412 	{
3413 		bound.row = TermWin.vts[page].saveLines + TermWin.nrow;
3414 		bound.col = TermWin.vts[page].bcol - 1;
3415 		dirnadd = 1;
3416 	}
3417 	row = mark->row + TermWin.vts[page].saveLines;
3418 	col = mark->col;
3419 	MAX_IT(col, 0);
3420 /* find the edge of a word */
3421 	stp = &(screen[page].text[row][col]);
3422 	w1 = DELIMIT_TEXT(*stp);
3423 #ifdef OLD_WORD_SELECTION
3424 	if (w1 == 1)
3425 	{
3426 		stp += dirnadd;
3427 		if (DELIMIT_TEXT(*stp) == 1)
3428 			goto Old_Word_Selection_You_Die;
3429 		col += dirnadd;
3430 		srp += dirnadd;
3431 	}
3432 	w1 = 0;
3433 #endif
3434 	srp = (&screen[page].rend[row][col]);
3435 	w2 = DELIMIT_REND(*srp);
3436 
3437 	for (;;)
3438 	{
3439 		for (; col != bound.col; col += dirnadd)
3440 		{
3441 			stp += dirnadd;
3442 			if (DELIMIT_TEXT(*stp) != w1)
3443 				break;
3444 			srp += dirnadd;
3445 			if (DELIMIT_REND(*srp) != w2)
3446 				break;
3447 		}
3448 		if ((col == bound.col) && (row != bound.row))
3449 		{
3450 			if (screen[page].tlen[(row - (dirn == UP))] == -1)
3451 			{
3452 				trow = row + dirnadd;
3453 				tcol = (dirn == UP) ? (TermWin.vts[page].bcol - 1) : 0;
3454 				if (screen[page].text[trow] == NULL)
3455 					break;
3456 				stp = &(screen[page].text[trow][tcol]);
3457 				srp = &(screen[page].rend[trow][tcol]);
3458 				if (DELIMIT_TEXT(*stp) != w1 || DELIMIT_REND(*srp) != w2)
3459 					break;
3460 				row = trow;
3461 				col = tcol;
3462 				continue;
3463 			}
3464 		}
3465 		break;
3466 	}
3467 #ifdef OLD_WORD_SELECTION
3468       Old_Word_Selection_You_Die:
3469 #endif
3470 	DSEL_ALEXIS(2,(stderr,
3471 		  "selection_delimit_word(%s,...) @ (r:%3d, c:%3d) has boundary (r:%3d, c:%3d)\n",
3472 		  (dirn == UP ? "up	" : "down"), mark->row, mark->col,
3473 		  row - TermWin.vts[page].saveLines, col));
3474 
3475 	if (dirn == DN)
3476 		col++;		/* put us on one past the end */
3477 
3478 /* Poke the values back in */
3479 	ret->row = row - TermWin.vts[page].saveLines;
3480 	ret->col = col;
3481 }
3482 
3483 /* ------------------------------------------------------------------------- */
3484 /*
3485  * Extend the selection to the specified x/y pixel location
3486  * EXT: button 3 press; button 1 or 3 drag
3487  * flag == 0 ==> button 1
3488  * flag == 1 ==> button 3 press
3489  * flag == 2 ==> button 3 motion
3490  */
3491 void selection_extend(int x, int y, int flag)
3492 {
3493 	int             col, row;
3494 
3495   DSEL_ALEXIS(2,(stderr, "selection_extend(%d, %d, %d)\n",x,y,flag));
3496 #ifdef THAI
3497 	col = ThaiPixel2Col(x, y);
3498 #else
3499 	col = Pixel2Col(x);
3500 #endif
3501 	row = Pixel2Row(y);
3502 	MAX_IT(row, 0);
3503 	MIN_IT(row, TermWin.nrow - 1);
3504 	MAX_IT(col, 0);
3505 	MIN_IT(col, TermWin.vts[TermWin.active_page].bcol);
3506 #ifndef OLD_SELECTION
3507 /*
3508  * If we're selecting characters (single click) then we must check first
3509  * if we are at the same place as the original mark.  If we are then
3510  * select nothing.  Otherwise, if we're to the right of the mark, you have to
3511  * be _past_ a character for it to be selected.
3512  */
3513 	if (((selection.clicks % 3) == 1) && !flag
3514 	    && (col == selection.mark.col
3515 		&& (row == selection.mark.row + TermWin.vts[TermWin.active_page].view_start)))
3516 	{
3517 	    /* select nothing */
3518 		selection.beg.row = selection.end.row = 0;
3519 		selection.beg.col = selection.end.col = 0;
3520 		selection.clicks = 4;
3521 		D_SELECT((stderr, "selection_extend() selection.clicks = 4"));
3522 		return;
3523 	}
3524 #endif
3525 	if (selection.clicks == 4)
3526 		selection.clicks = 1;
3527 	f_selection_extend_colrow(TermWin.active_page,col, row, !!flag,	/* ? button 3      */
3528 				flag == 1 ? 1 : 0,	/* ? button press  */
3529 				0);	/* no click change */
3530 }
3531 
3532 /* ------------------------------------------------------------------------- */
3533 /*
3534  * Extend the selection to the specified col/row
3535  */
3536 void f_selection_extend_colrow(int page,int col, int row, int button3, int buttonpress,int clickchange)
3537 {
3538 	int             end_col;
3539 	row_col_t       pos;
3540 	enum
3541 	{
3542 		LEFT, RIGHT
3543 	}
3544 	closeto = RIGHT;
3545 
3546 #ifdef MULTICHAR_SET
3547 	int             c, r;
3548 #endif
3549 
3550 	DSEL_ALEXIS(2,(stderr,
3551 		  "selection_extend_colrow(c:%d, r:%d, %d, %d) clicks:%d\n", col,
3552 		  row, button3, buttonpress, selection.clicks));
3553 	DSEL_ALEXIS(2,(stderr,
3554 		  "selection_extend_colrow() ENT  b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)\n",
3555 		  selection.beg.row, selection.beg.col, selection.mark.row,
3556 		  selection.mark.col, selection.end.row, selection.end.col));
3557 
3558 	switch (selection.op)
3559 	{
3560 	case SELECTION_INIT:
3561 		CLEAR_SELECTION;
3562 		selection.op = SELECTION_BEGIN;
3563 	    /* FALLTHROUGH */
3564 	case SELECTION_BEGIN:
3565 		if (row != selection.mark.row || col != selection.mark.col
3566 		    || (!button3 && buttonpress))
3567 			selection.op = SELECTION_CONT;
3568 		break;
3569 	case SELECTION_DONE:
3570 		selection.op = SELECTION_CONT;
3571 	    /* FALLTHROUGH */
3572 	case SELECTION_CONT:
3573 		break;
3574 	case SELECTION_CLEAR:
3575 		selection_start_colrow(col, row);
3576 	    /* FALLTHROUGH */
3577 	default:
3578 		return;
3579 	}
3580 
3581 	pos.col = col;
3582 	pos.row = row;
3583 
3584 	pos.row -= TermWin.vts[page].view_start;	/* adjust for scroll */
3585 
3586 #ifdef OLD_SELECTION
3587 /*
3588  * This mimics some of the selection behaviour of version 2.20 and before.
3589  * There are no ``selection modes'', button3 is always character extension.
3590  * Note: button3 drag is always available, c.f. v2.20
3591  * Selection always terminates (left or right as appropriate) at the mark.
3592  */
3593 	{
3594 		static int      hate_those_clicks = 0;	/* a.k.a. keep mark position */
3595 
3596 		if (selection.clicks == 1 || button3)
3597 		{
3598 			if (hate_those_clicks)
3599 			{
3600 				selection.mark.row = selection.beg.row;
3601 				selection.mark.col = selection.beg.col;
3602 				hate_those_clicks = 0;
3603 			}
3604 			if (ROWCOL_IS_BEFORE(pos, selection.beg))
3605 			{
3606 				selection.end.row = selection.beg.row;
3607 				selection.end.col = selection.beg.col + 1;
3608 				selection.beg.row = pos.row;
3609 				selection.beg.col = pos.col;
3610 			} else
3611 			{
3612 				selection.beg.row = selection.mark.row;
3613 				selection.beg.col = selection.mark.col;
3614 				selection.end.row = pos.row;
3615 				selection.end.col = pos.col + 1;
3616 			}
3617 		} else if (selection.clicks == 2)
3618 		{
3619 			f_selection_delimit_word(page,UP, &(selection.mark), &(selection.beg));
3620 			f_selection_delimit_word(page,DN, &(selection.mark), &(selection.end));
3621 			hate_those_clicks = 1;
3622 		} else if (selection.clicks == 3)
3623 		{
3624 			selection.beg.row = selection.end.row = selection.mark.row;
3625 			selection.beg.col = 0;
3626 			selection.end.col = TermWin.vts[page].bcol;
3627 			hate_those_clicks = 1;
3628 		}
3629 	}
3630 #else				/* ! OLD_SELECTION */
3631 /*
3632  * This is mainly xterm style selection with a couple of differences, mainly
3633  * in the way button3 drag extension works.
3634  * We're either doing: button1 drag; button3 press; or button3 drag
3635  *  a) button1 drag : select around a midpoint/word/line - that point/word/line
3636  *     is always at the left/right edge of the selection.
3637  *  b) button3 press: extend/contract character/word/line at whichever edge of
3638  *     the selection we are closest to.
3639  *  c) button3 drag : extend/contract character/word/line - we select around
3640  *     a point/word/line which is either the start or end of the selection
3641  *     and it was decided by whichever point/word/line was `fixed' at the
3642  *     time of the most recent button3 press
3643  */
3644 	if (button3 && buttonpress)
3645 	{			/* button3 press */
3646 	    /*
3647 	     * first determine which edge of the selection we are closest to
3648 	     */
3649 		if (ROWCOL_IS_BEFORE(pos, selection.beg)
3650 		    || (!ROWCOL_IS_AFTER(pos, selection.end)
3651 			&& (((pos.col - selection.beg.col)
3652 			     + ((pos.row - selection.beg.row) * TermWin.vts[page].bcol))
3653 			    < ((selection.end.col - pos.col)
3654 			       +
3655 			       ((selection.end.row -pos.row) * TermWin.vts[page].bcol)))))
3656 			closeto = LEFT;
3657 		if (closeto == LEFT)
3658 		{
3659 			selection.beg.row = pos.row;
3660 			selection.beg.col = pos.col;
3661 			selection.mark.row = selection.end.row;
3662 			selection.mark.col =
3663 			    selection.end.col - (selection.clicks == 2);
3664 		} else
3665 		{
3666 			selection.end.row = pos.row;
3667 			selection.end.col = pos.col;
3668 			selection.mark.row = selection.beg.row;
3669 			selection.mark.col = selection.beg.col;
3670 		}
3671 	} else
3672 	{			/* button1 drag or button3 drag */
3673 		if (ROWCOL_IS_AFTER(selection.mark, pos))
3674 		{
3675 			if ((selection.mark.row == selection.end.row)
3676 			    && (selection.mark.col == selection.end.col)
3677 			    && clickchange && selection.clicks == 2)
3678 				selection.mark.col--;
3679 			selection.beg.row = pos.row;
3680 			selection.beg.col = pos.col;
3681 			selection.end.row = selection.mark.row;
3682 			selection.end.col =
3683 			    selection.mark.col + (selection.clicks == 2);
3684 		} else
3685 		{
3686 			selection.beg.row = selection.mark.row;
3687 			selection.beg.col = selection.mark.col;
3688 			selection.end.row = pos.row;
3689 			selection.end.col = pos.col;
3690 		}
3691 	}
3692 
3693 	if (selection.clicks == 1)
3694 	{
3695 		end_col = screen[page].tlen[selection.beg.row + TermWin.vts[page].saveLines];
3696 		if (end_col != -1 && selection.beg.col > end_col)
3697 		{
3698 #if 1
3699 			selection.beg.col = TermWin.vts[page].bcol;
3700 #else
3701 			if (selection.beg.row != selection.end.row)
3702 				selection.beg.col = TermWin.vts[page].bcol;
3703 			else
3704 				selection.beg.col = selection.mark.col;
3705 #endif
3706 		}
3707 		end_col = screen[page].tlen[selection.end.row + TermWin.vts[page].saveLines];
3708 		if (end_col != -1 && selection.end.col > end_col)
3709 			selection.end.col = TermWin.vts[page].bcol;
3710 
3711 # ifdef MULTICHAR_SET
3712 		if (selection.beg.col > 0)
3713 		{
3714 			r = selection.beg.row + TermWin.vts[page].saveLines;
3715 			c = selection.beg.col;
3716 			if (((screen[page].rend[r][c] & RS_multiMask) == RS_multi2)
3717 			    && ((screen[page].rend[r][c - 1] & RS_multiMask) ==
3718 				RS_multi1))
3719 				selection.beg.col--;
3720 		}
3721 		if (selection.end.col < TermWin.vts[page].bcol)
3722 		{
3723 			r = selection.end.row + TermWin.vts[page].saveLines;
3724 			c = selection.end.col;
3725 			if (((screen[page].rend[r][c - 1] & RS_multiMask) == RS_multi1)
3726 			    && ((screen[page].rend[r][c] & RS_multiMask) == RS_multi2))
3727 				selection.end.col++;
3728 		}
3729 # endif				/* MULTICHAR_SET */
3730 	} else if (selection.clicks == 2)
3731 	{
3732 		if (ROWCOL_IS_AFTER(selection.end, selection.beg))
3733 			selection.end.col--;
3734 		f_selection_delimit_word(page,UP, &(selection.beg), &(selection.beg));
3735 		f_selection_delimit_word(page,DN, &(selection.end), &(selection.end));
3736 	} else if (selection.clicks == 3)
3737 	{
3738 		if (ROWCOL_IS_AFTER(selection.mark, selection.beg))
3739 			selection.mark.col++;
3740 		selection.beg.col = 0;
3741 		selection.end.col = TermWin.vts[page].bcol;
3742 	}
3743 	if (button3 && buttonpress)
3744 	{			/* mark may need to be changed */
3745 		if (closeto == LEFT)
3746 		{
3747 			selection.mark.row = selection.end.row;
3748 			selection.mark.col = selection.end.col - (selection.clicks == 2);
3749 		} else
3750 		{
3751 			selection.mark.row = selection.beg.row;
3752 			selection.mark.col = selection.beg.col;
3753 		}
3754 	}
3755 #endif				/* ! OLD_SELECTION */
3756 	DSEL_ALEXIS(2,(stderr,
3757 		  "selection_extend_colrow() EXIT b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)\n",
3758 		  selection.beg.row, selection.beg.col, selection.mark.row,
3759 		  selection.mark.col, selection.end.row, selection.end.col));
3760 }
3761 
3762 /* ------------------------------------------------------------------------- */
3763 /*
3764  * Double click on button 3 when already selected
3765  * EXT: button 3 double click
3766  */
3767 /* PROTO */
3768 void
3769 selection_rotate(int x, int y)
3770 {
3771   DSEL_ALEXIS(2,(stderr, "selection_rotate(%d, %d)\n",x,y));
3772 	selection.clicks = selection.clicks % 3 + 1;
3773 #ifdef THAI
3774 	f_selection_extend_colrow(TermWin.active_page,ThaiPixel2Col(x, y), Pixel2Row(y), 1, 0, 1);
3775 #else
3776 	f_selection_extend_colrow(TermWin.active_page,Pixel2Col(x), Pixel2Row(y), 1, 0, 1);
3777 #endif
3778 }
3779 
3780 /* ------------------------------------------------------------------------- */
3781 /*
3782  * On some systems, the Atom typedef is 64 bits wide.  We need to have a type
3783  * that is exactly 32 bits wide, because a format of 64 is not allowed by
3784  * the X11 protocol.
3785  */
3786 typedef CARD32  Atom32;
3787 
3788 /* ------------------------------------------------------------------------- */
3789 /*
3790  * Respond to a request for our current selection
3791  * EXT: SelectionRequest
3792  */
3793 
3794 void selection_send(XSelectionRequestEvent * rq)
3795 {
3796 	XEvent          ev;
3797 	Atom32          target_list[2];
3798 	static Atom     xa_targets = None;
3799 
3800 	if (xa_targets == None)
3801 		xa_targets = XInternAtom(Xdisplay, "TARGETS", False);
3802 
3803 	ev.xselection.type = SelectionNotify;
3804 	ev.xselection.property = None;
3805 	ev.xselection.display = rq->display;
3806 	ev.xselection.requestor = rq->requestor;
3807 	ev.xselection.selection = rq->selection;
3808 	ev.xselection.target = rq->target;
3809 	ev.xselection.time = rq->time;
3810 
3811 	if (rq->target == xa_targets)
3812 	{
3813 		target_list[0] = (Atom32) xa_targets;
3814 		target_list[1] = (Atom32) XA_STRING;
3815 		XChangeProperty(Xdisplay, rq->requestor, rq->property,
3816 				rq->target, (8 * sizeof(target_list[0])),
3817 				PropModeReplace, (unsigned char *)target_list,
3818 				(sizeof(target_list) /
3819 				 sizeof(target_list[0])));
3820 		ev.xselection.property = rq->property;
3821 	} else if (rq->target == XA_STRING)
3822 	{
3823 		XChangeProperty(Xdisplay, rq->requestor, rq->property,
3824 				rq->target, 8, PropModeReplace, selection.text,
3825 				selection.len);
3826 		ev.xselection.property = rq->property;
3827 	}
3828 	XSendEvent(Xdisplay, rq->requestor, False, 0, &ev);
3829 }
3830 
3831 /* ------------------------------------------------------------------------- *
3832  *                              MOUSE ROUTINES                               *
3833  * ------------------------------------------------------------------------- */
3834 
3835 /*
3836  * return col/row values corresponding to x/y pixel values
3837  */
3838 /* PROTO */
3839 void
3840 pixel_position(int *x, int *y)
3841 {
3842 #ifdef THAI
3843 	*x = ThaiPixel2Col(*x, *y);
3844 #else
3845 	*x = Pixel2Col(*x);
3846 #endif
3847     /* MAX_IT(*x, 0); MIN_IT(*x, TermWin.bcol - 1); */
3848 	*y = Pixel2Row(*y);
3849     /* MAX_IT(*y, 0); MIN_IT(*y, TermWin.nrow - 1); */
3850 }
3851 
3852 /* ------------------------------------------------------------------------- */
3853 /* ARGSUSED */
3854 /* PROTO */
3855 void
3856 mouse_tracking(int report, int x, int y, int firstrow, int lastrow)
3857 {
3858 /* TODO */
3859 }
3860 
3861 /* ------------------------------------------------------------------------- *
3862  *                              DEBUG ROUTINES                               *
3863  * ------------------------------------------------------------------------- */
3864 /* ARGSUSED */
3865 /* PROTO */
3866 void
3867 debug_PasteIt(unsigned char *data, int nitems)
3868 {
3869 /* TODO */
3870 }
3871 
3872 /* ------------------------------------------------------------------------- */
3873 /* PROTO */
3874 void
3875 debug_colors(void)
3876 {
3877 	int             color;
3878 	char           *name[] = { "fg", "bg",
3879 		"black", "red", "green", "yellow", "blue", "magenta", "cyan",
3880 		    "white"
3881 	};
3882 
3883 	fprintf(stderr, "Color ( ");
3884 	if (rstyle & RS_RVid)
3885 		fprintf(stderr, "rvid ");
3886 	if (rstyle & RS_Bold)
3887 		fprintf(stderr, "bold ");
3888 	if (rstyle & RS_Blink)
3889 		fprintf(stderr, "blink ");
3890 	if (rstyle & RS_Uline)
3891 		fprintf(stderr, "uline ");
3892 	fprintf(stderr, "): ");
3893 
3894 	color = GET_FGCOLOR(rstyle);
3895 #ifndef NO_BRIGHTCOLOR
3896 	if (color >= minBrightCOLOR && color <= maxBrightCOLOR)
3897 	{
3898 		color -= (minBrightCOLOR - minCOLOR);
3899 		fprintf(stderr, "bright ");
3900 	}
3901 #endif
3902 	fprintf(stderr, "%s on ", name[color]);
3903 
3904 	color = GET_BGCOLOR(rstyle);
3905 #ifndef NO_BRIGHTCOLOR
3906 	if (color >= minBrightCOLOR && color <= maxBrightCOLOR)
3907 	{
3908 		color -= (minBrightCOLOR - minCOLOR);
3909 		fprintf(stderr, "bright ");
3910 	}
3911 #endif
3912 	fprintf(stderr, "%s\n", name[color]);
3913 }
3914