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