1 /*--------------------------------*-C-*---------------------------------*
2  * File:	screen.c
3  *----------------------------------------------------------------------*
4  *
5  * All portions of code are copyright by their respective author/s.
6  * Copyright (c) 1997-2001   Geoff Wing <gcw@pobox.com>
7  * Copyright (C) 2000,2001   Teepanis Chachiyo <teepanis@physics.purdue.edu>
8  * Copyright (c) 2001        Marius Gedminas <marius.gedminas@uosis.mif.vu.lt>
9  * Copyright (c) 2003        David Hull
10  * Copyright (c) 2003        Yamanobe Kiichiro <yamky@cocoa.freemail.ne.jp>
11  * Copyright (c) 2003        Mamoru Komachi <usata@usata.org>
12  * Copyright (c) 2005        William P. Y. Hadisoeseno <williampoetra@users.sourceforge.net>
13  * Copyright (c) 2004-2005   Jingmin Zhou <jimmyzhou@users.sourceforge.net>
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28  *----------------------------------------------------------------------*/
29 /*
30 ** $Id: screen.c,v 1.137 2005/06/24 04:26:55 cvs Exp $
31 */
32 
33 #include "../config.h"
34 #define INTERN_SCREEN
35 #include "rxvt.h"
36 
37 
38 #ifdef DEBUG_VERBOSE
39 #define DEBUG_LEVEL 1
40 #else
41 #define DEBUG_LEVEL 0
42 #endif
43 
44 #if DEBUG_LEVEL
45 #define DBG_MSG(d,x) if(d <= DEBUG_LEVEL) fprintf x
46 #else
47 #define DBG_MSG(d,x)
48 #endif
49 
50 
51 /* ------------------------------------------------------------------------- */
52 #ifdef MULTICHAR_SET
53 #define RESET_CHSTAT(R, P)					\
54 	if (PVTS((R),(P))->chstat == WBYTE)	\
55 		PVTS((R),(P))->chstat = SBYTE, PVTS((R),(P))->lost_multi = 1
56 #else
57 # define RESET_CHSTAT(R, P)
58 #endif
59 
60 /* ------------------------------------------------------------------------- */
61 #define PROP_SIZE		16384
62 
63 /* ------------------------------------------------------------------------- *
64  *			 GENERAL SCREEN AND SELECTION UPDATE ROUTINES				  *
65  * ------------------------------------------------------------------------- */
66 
67 /*
68 ** If hihibit scrolling on tty output, we should keep the view_start.
69 ** Otherwise, we set it to zero.
70 */
71 #define ZERO_SCROLLBACK(R, P)						\
72 	if (!((R)->Options & Opt_scrollTtyOutputInhibit))	\
73 		(R)->vts[(P)]->view_start = 0
74 
75 #define CLEAR_SELECTION(R)						\
76 	(R)->selection.beg.row = \
77 	(R)->selection.beg.col = \
78 	(R)->selection.end.row = \
79 	(R)->selection.end.col = 0
80 
81 #define CLEAR_ALL_SELECTION(R)					\
82 	(R)->selection.beg.row = \
83 	(R)->selection.beg.col = \
84 	(R)->selection.mark.row = \
85 	(R)->selection.mark.col = \
86 	(R)->selection.end.row = \
87 	(R)->selection.end.col = 0
88 
89 #define ROW_AND_COL_IS_AFTER(A, B, C, D)				\
90 	(((A) > (C)) || (((A) == (C)) && ((B) > (D))))
91 #define ROW_AND_COL_IS_BEFORE(A, B, C, D)				\
92 	(((A) < (C)) || (((A) == (C)) && ((B) < (D))))
93 #define ROW_AND_COL_IN_ROW_AFTER(A, B, C, D)			\
94 	(((A) == (C)) && ((B) > (D)))
95 #define ROW_AND_COL_IN_ROW_AT_OR_AFTER(A, B, C, D)		\
96 	(((A) == (C)) && ((B) >= (D)))
97 #define ROW_AND_COL_IN_ROW_BEFORE(A, B, C, D)			\
98 	(((A) == (C)) && ((B) < (D)))
99 #define ROW_AND_COL_IN_ROW_AT_OR_BEFORE(A, B, C, D)		\
100 	(((A) == (C)) && ((B) <= (D)))
101 
102 /* these must be row_col_t */
103 #define RC_AFTER(X, Y)						\
104 	ROW_AND_COL_IS_AFTER((X).row, (X).col, (Y).row, (Y).col)
105 #define RC_BEFORE(X, Y)						\
106 	ROW_AND_COL_IS_BEFORE((X).row, (X).col, (Y).row, (Y).col)
107 #define RC_ROW_AFTER(X, Y)					\
108 	ROW_AND_COL_IN_ROW_AFTER((X).row, (X).col, (Y).row, (Y).col)
109 #define RC_ROW_BEFORE(X, Y)					\
110 	ROW_AND_COL_IN_ROW_BEFORE((X).row, (X).col, (Y).row, (Y).col)
111 #define RC_ROW_ATAFTER(X, Y)					\
112 	ROW_AND_COL_IN_ROW_AT_OR_AFTER((X).row, (X).col, (Y).row, (Y).col)
113 #define RC_ROW_ATBEFORE(X, Y)				\
114 	ROW_AND_COL_IN_ROW_AT_OR_BEFORE((X).row, (X).col, (Y).row, (Y).col)
115 
116 /*
117  * CLEAR_ROWS : clear <num> rows starting from row <row>
118  * CLEAR_CHARS: clear <num> chars starting from pixel position <x,y>
119  * ERASE_ROWS : set <num> rows starting from row <row> to the foreground colour
120  */
121 #define drawBuffer	(PVTS(r, page)->vt)
122 
123 #define CLEAR_ROWS(row, num)							\
124 	if (r->TermWin.mapped)								\
125 		rxvt_clear_area (r, page,						\
126 			r->TermWin.int_bwidth, Row2Pixel(row),		\
127 			VT_WIDTH(r), (unsigned int)Height2Pixel(num))
128 
129 
130 #define CLEAR_CHARS(x, y, num)						\
131 	if (r->TermWin.mapped)							\
132 		rxvt_clear_area (r, page, x, y,				\
133 			(unsigned int)Width2Pixel(num),			\
134 			(unsigned int)Height2Pixel(1))
135 
136 
137 #define ERASE_ROWS(row, num)						\
138 	rxvt_fill_rectangle (r,	page,					\
139 		   r->TermWin.int_bwidth, Row2Pixel(row),	\
140 		   VT_WIDTH(r),	(unsigned int)Height2Pixel(num))
141 
142 
143 #ifdef DONT_SELECT_TRAILING_SPACES
144 # define STRIP_TRAILING_SPACE(str, fence)			\
145 	while (str > fence && ' ' == str[-1])			\
146 		str --;
147 #endif
148 
149 
150 /* Here are some simple macros for convenience */
151 #undef CURROW
152 #undef CURCOL
153 #undef SVLINES
154 #undef VSTART
155 #define CURROW		(PSCR(r, page).cur.row)
156 #define CURCOL		(PSCR(r, page).cur.col)
157 #define SVLINES		(PVTS(r, page)->saveLines)
158 #define VSTART		(PVTS(r, page)->view_start)
159 
160 
161 /*--------------------------------------------------------------------*
162  *         BEGIN `INTERNAL' ROUTINE PROTOTYPES                        *
163  *--------------------------------------------------------------------*/
164 void rxvt_blank_line              (text_t*, rend_t*, unsigned int, rend_t);
165 void rxvt_blank_screen_mem        (rxvt_t*, int, text_t**, rend_t **, unsigned int, rend_t);
166 void rxvt_scr_reset_realloc       (rxvt_t*, int);
167 void rxvt_scr_delete_row          (rxvt_t*, int);
168 void rxvt_scr_add_row             (rxvt_t*, int, unsigned int, unsigned int);
169 void inline rxvt_clear_area       (rxvt_t*, int page, int x, int y, unsigned int w, unsigned int h);
170 void inline rxvt_fill_rectangle   (rxvt_t*, int page, int x, int y, unsigned int w, unsigned int h);
171 void rxvt_scr_draw_string         (rxvt_t* r, int page, int x, int y, char* str, int len, int drawfunc, RUINT16T fore, RUINT16T back);
172 void rxvt_scr_adjust_col          (rxvt_t*, int, unsigned int);
173 void rxvt_set_font_style          (rxvt_t*, int);
174 int  rxvt_scr_change_view         (rxvt_t*, int, RUINT16T);
175 void rxvt_scr_reverse_selection   (rxvt_t*, int);
176 void rxvt_PasteIt                 (rxvt_t*, int, const unsigned char*, unsigned int);
177 int  rxvt_selection_request_other (rxvt_t*, int, Atom, int);
178 void rxvt_selection_start_colrow  (rxvt_t*, int, int, int);
179 void rxvt_selection_delimit_word  (rxvt_t*, int, enum page_dirn, const row_col_t*, row_col_t*);
180 #ifdef MULTICHAR_SET
181 void rxvt_selection_adjust_kanji  (rxvt_t*, int);
182 #endif
183 void rxvt_selection_extend_colrow (rxvt_t*, int, RINT32T, RINT32T, int, int, int);
184 #ifndef NO_FRILLS
185 void rxvt_selection_trim          (rxvt_t*, int);
186 #endif
187 #ifdef TEXT_SHADOW
188 void rxvt_set_clipping            (rxvt_t*, GC, int, int, int, int, int*, int*);
189 void rxvt_free_clipping           (rxvt_t*, GC);
190 #endif
191 #ifdef XFT_SUPPORT
192 # ifndef NO_BOLDFONT
193 int  rxvt_switch_bold_font        (rxvt_t* r);
194 int  rxvt_restore_bold_font       (rxvt_t* r);
195 # endif
196 #endif	/* XFT_SUPPORT */
197 /*--------------------------------------------------------------------*
198  *         END   `INTERNAL' ROUTINE PROTOTYPES                        *
199  *--------------------------------------------------------------------*/
200 
201 
202 
203 /* ------------------------------------------------------------------------- *
204  *						SCREEN `COMMON' ROUTINES						   *
205  * ------------------------------------------------------------------------- */
206 /* Fill part/all of a line with blanks. */
207 /* INTPROTO */
208 void
rxvt_blank_line(text_t * et,rend_t * er,unsigned int width,rend_t efs)209 rxvt_blank_line(text_t *et, rend_t *er, unsigned int width, rend_t efs)
210 {
211 	MEMSET(et, ' ', (size_t)width);
212 	efs &= ~RS_baseattrMask;
213 	for (; width--;)
214 		*er++ = efs;
215 }
216 
217 /* ------------------------------------------------------------------------- */
218 /* Fill a full line with blanks - make sure it is allocated first */
219 /* INTPROTO */
220 void
rxvt_blank_screen_mem(rxvt_t * r,int page,text_t ** tp,rend_t ** rp,unsigned int row,rend_t efs)221 rxvt_blank_screen_mem(rxvt_t* r, int page, text_t **tp, rend_t **rp, unsigned int row, rend_t efs)
222 {
223 	int			 width = r->TermWin.ncol;
224 	rend_t		 *er;
225 
226 	assert ((tp[row] && rp[row]) ||
227 		(tp[row] == NULL && rp[row] == NULL));
228 
229 	/* possible integer overflow? */
230 	assert (width > 0);
231 	assert (sizeof (text_t) * width > 0);
232 	assert (sizeof (rend_t) * width > 0);
233 
234 	if (tp[row] == NULL) {
235 		tp[row] = rxvt_malloc(sizeof(text_t) * width);
236 		rp[row] = rxvt_malloc(sizeof(rend_t) * width);
237 	}
238 	MEMSET(tp[row], ' ', width);
239 	efs &= ~RS_baseattrMask;
240 	for (er = rp[row]; width--;)
241 		*er++ = efs;
242 }
243 
244 
245 
246 /* ------------------------------------------------------------------------- *
247  *						  SCREEN INITIALISATION							*
248  * ------------------------------------------------------------------------- */
249 /* EXTPROTO */
250 void
rxvt_init_screen(rxvt_t * r)251 rxvt_init_screen (rxvt_t* r)
252 {
253 	int		p;
254 	int		ncol = r->TermWin.ncol;
255 
256 	/* first time, we don't have r->tabstop yet */
257 	DBG_MSG(1, (stderr, "allocate r->tabstop as %d\n", ncol));
258 	assert (ncol > 0);	/* possible integer overflow? */
259 	r->tabstop = rxvt_malloc(ncol * sizeof(char));
260 	for (p = 0; p < ncol; p++)
261 		r->tabstop[p] = (p % TABSTOP_SIZE == 0) ? 1 : 0;
262 }
263 
264 
265 void
rxvt_scr_alloc(rxvt_t * r,int page)266 rxvt_scr_alloc (rxvt_t* r, int page)
267 {
268 	unsigned int	ncol, nrow, total_rows;
269 	unsigned int	p, q;
270 
271 
272 	DBG_MSG(1, (stderr, "rxvt_scr_alloc %d ()\n", page));
273 	ncol = r->TermWin.ncol;
274 	nrow = r->TermWin.nrow;
275 	total_rows = nrow + SVLINES;
276 
277 	/*
278 	** First time called so just malloc everything : don't rely on
279 	** realloc
280 	** Note: this is still needed so that all the scrollback lines
281 	** are NULL
282 	*/
283 	PVTS(r, page)->buf_text = rxvt_calloc(total_rows, sizeof(text_t*));
284 	PVTS(r, page)->buf_rend = rxvt_calloc(total_rows, sizeof(rend_t*));
285 
286 	PVTS(r, page)->drawn_text = rxvt_calloc(nrow, sizeof(text_t*));
287 	PVTS(r, page)->drawn_rend = rxvt_calloc(nrow, sizeof(rend_t*));
288 
289 	PSCR(r, page).text = rxvt_calloc(total_rows, sizeof(text_t*));
290 	PSCR(r, page).tlen = rxvt_calloc(total_rows, sizeof(RINT16T));
291 	PSCR(r, page).rend = rxvt_calloc(total_rows, sizeof(rend_t*));
292 
293 #if NSCREENS
294 	PVTS(r, page)->swap.text = rxvt_calloc(nrow, sizeof(text_t*));
295 	PVTS(r, page)->swap.tlen = rxvt_calloc(nrow, sizeof(RINT16T));
296 	PVTS(r, page)->swap.rend = rxvt_calloc(nrow, sizeof(rend_t*));
297 #endif
298 
299 	for (p = 0; p < nrow; p++) {
300 		q = p + SVLINES;
301 		rxvt_blank_screen_mem (r, page, PSCR(r, page).text,
302 			PSCR(r, page).rend, q, DEFAULT_RSTYLE);
303 		PSCR(r, page).tlen[q] = 0;
304 #if NSCREENS
305 		rxvt_blank_screen_mem (r, page, PVTS(r, page)->swap.text,
306 			PVTS(r, page)->swap.rend, p, DEFAULT_RSTYLE);
307 		PVTS(r, page)->swap.tlen[p] = 0;
308 #endif
309 
310 		rxvt_blank_screen_mem (r, page, PVTS(r, page)->drawn_text,
311 			PVTS(r, page)->drawn_rend, p, DEFAULT_RSTYLE);
312 	}
313 	PVTS(r, page)->nscrolled = 0;	/* no saved lines */
314 	PSCR(r, page).flags = Screen_DefaultFlags;
315 	PSCR(r, page).cur.row = 0;
316 	PSCR(r, page).cur.col = 0;
317 	PSCR(r, page).charset = 0;
318 	PVTS(r, page)->current_screen = PRIMARY;
319 	rxvt_scr_cursor(r, page, SAVE);
320 #if NSCREENS
321 	PVTS(r, page)->swap.flags = Screen_DefaultFlags;
322 	PVTS(r, page)->swap.cur.row = 0;
323 	PVTS(r, page)->swap.cur.col = 0;
324 	PVTS(r, page)->swap.charset = 0;
325 	PVTS(r, page)->current_screen = SECONDARY;
326 	rxvt_scr_cursor(r, page, SAVE);
327 	PVTS(r, page)->current_screen = PRIMARY;
328 #endif
329 
330 	PVTS(r, page)->rstyle = DEFAULT_RSTYLE;
331 	PVTS(r, page)->rvideo = 0;
332 	MEMSET(&(PVTS(r, page)->charsets), 'B', sizeof(PVTS(r, page)->charsets));
333 #ifdef MULTICHAR_SET
334 	PVTS(r, page)->multi_byte = 0;
335 	PVTS(r, page)->lost_multi = 0;
336 	PVTS(r, page)->chstat = SBYTE;
337 #endif
338 
339 	/* Now set screen initialization flag */
340 	PVTS(r, page)->init_screen = 1;
341 }
342 
343 
344 
345 /* INTPROTO */
346 void
rxvt_scr_reset_realloc(rxvt_t * r,int page)347 rxvt_scr_reset_realloc(rxvt_t* r, int page)
348 {
349 	unsigned int   total_rows, nrow;
350 
351 
352 	DBG_MSG(2, (stderr, "rxvt_scr_reset_realloc %d ()\n", page));
353 	nrow = r->TermWin.nrow;
354 	total_rows = nrow + SVLINES;
355 
356 	PSCR(r, page).text = rxvt_realloc (
357 		PSCR(r, page).text, total_rows * sizeof(text_t *));
358 	PSCR(r, page).tlen = rxvt_realloc (
359 		PSCR(r, page).tlen, total_rows * sizeof(RINT16T));
360 	PSCR(r, page).rend = rxvt_realloc (
361 		PSCR(r, page).rend, total_rows * sizeof(rend_t *));
362 
363 #if NSCREENS
364 	PVTS(r, page)->swap.text   = rxvt_realloc (
365 		PVTS(r, page)->swap.text, nrow * sizeof(text_t *));
366 	PVTS(r, page)->swap.tlen   = rxvt_realloc (
367 		PVTS(r, page)->swap.tlen  , total_rows * sizeof(RINT16T));
368 	PVTS(r, page)->swap.rend   = rxvt_realloc (
369 		PVTS(r, page)->swap.rend, nrow * sizeof(rend_t *));
370 #endif
371 
372 	PVTS(r, page)->buf_text	= rxvt_realloc (
373 		PVTS(r, page)->buf_text, total_rows * sizeof(text_t *));
374 	PVTS(r, page)->buf_rend	= rxvt_realloc (
375 		PVTS(r, page)->buf_rend, total_rows * sizeof(rend_t *));
376 
377 	PVTS(r, page)->drawn_text  = rxvt_realloc (
378 		PVTS(r, page)->drawn_text, nrow * sizeof(text_t *));
379 	PVTS(r, page)->drawn_rend  = rxvt_realloc (
380 		PVTS(r, page)->drawn_rend, nrow * sizeof(rend_t *));
381 }
382 
383 
384 /* INTPROTO */
385 void
rxvt_scr_delete_row(rxvt_t * r,int page)386 rxvt_scr_delete_row (rxvt_t* r, int page)
387 {
388 	unsigned int	nrow, prev_nrow;
389 	unsigned int	p, q;
390 	register int	i;
391 
392 
393 	DBG_MSG(2, (stderr, "rxvt_scr_delete_row %d ()\n", page));
394 	nrow = r->TermWin.nrow;
395 	prev_nrow = PVTS(r, page)->prev_nrow;
396 
397 	/* delete rows */
398 	i = min(PVTS(r, page)->nscrolled, prev_nrow - nrow);
399 	rxvt_scroll_text(r, page, 0, (int)prev_nrow - 1, i, 1);
400 
401 	for (p = nrow; p < prev_nrow; p++) {
402 		q = p + SVLINES;
403 		if (PSCR(r, page).text[q]) {
404 			assert(PSCR(r, page).rend[q]);
405 			free(PSCR(r, page).text[q]);
406 			PSCR(r, page).text[q] = NULL;
407 			free(PSCR(r, page).rend[q]);
408 			PSCR(r, page).rend[q] = NULL;
409 		}
410 #if NSCREENS
411 		if (PVTS(r, page)->swap.text[p]) {
412 			assert(PVTS(r, page)->swap.rend[p]);
413 			free(PVTS(r, page)->swap.text[p]);
414 			PVTS(r, page)->swap.text[p] = NULL;
415 			free(PVTS(r, page)->swap.rend[p]);
416 			PVTS(r, page)->swap.rend[p] = NULL;
417 		}
418 #endif
419 		assert (PVTS(r, page)->drawn_text[p]);
420 		assert (PVTS(r, page)->drawn_rend[p]);
421 		free(PVTS(r, page)->drawn_text[p]);
422 		PVTS(r, page)->drawn_text[p] = NULL;
423 		free(PVTS(r, page)->drawn_rend[p]);
424 		PVTS(r, page)->drawn_rend[p] = NULL;
425 	}
426 
427 	/* we have fewer rows so fix up cursor position */
428 	MIN_IT(PSCR(r, page).cur.row, (RINT32T)nrow - 1);
429 #if NSCREENS
430 	MIN_IT(PVTS(r, page)->swap.cur.row, (RINT32T)nrow - 1);
431 #endif
432 
433 	rxvt_scr_reset_realloc (r, page);	/* realloc _last_ */
434 }
435 
436 
437 /* INTPROTO */
438 void
rxvt_scr_add_row(rxvt_t * r,int page,unsigned int total_rows,unsigned int prev_total_rows)439 rxvt_scr_add_row (rxvt_t* r, int page, unsigned int total_rows, unsigned int prev_total_rows)
440 {
441 	unsigned int	nrow, prev_nrow;
442 	unsigned int	p;
443 	register int	i;
444 
445 
446 	DBG_MSG(2, (stderr, "rxvt_scr_add_row %d ()\n", page));
447 	nrow = r->TermWin.nrow;
448 	prev_nrow = PVTS(r, page)->prev_nrow;
449 
450 	/* add rows */
451 	rxvt_scr_reset_realloc(r, page);	/* realloc _first_ */
452 
453 	i = min(PVTS(r, page)->nscrolled, nrow - prev_nrow);
454 	for (p = prev_total_rows; p < total_rows; p++) {
455 		PSCR(r, page).tlen[p] = 0;
456 		PSCR(r, page).text[p] = NULL;
457 		PSCR(r, page).rend[p] = NULL;
458 	}
459 
460 	for (p = prev_total_rows; p < total_rows - i; p++)
461 		rxvt_blank_screen_mem (r, page, PSCR(r, page).text,
462 			PSCR(r, page).rend, p, DEFAULT_RSTYLE);
463 
464 	for (p = prev_nrow; p < nrow; p++) {
465 #if NSCREENS
466 		PVTS(r, page)->swap.tlen[p] = 0;
467 		PVTS(r, page)->swap.text[p] = NULL;
468 		PVTS(r, page)->swap.rend[p] = NULL;
469 		rxvt_blank_screen_mem (r, page, PVTS(r, page)->swap.text,
470 			PVTS(r, page)->swap.rend, p, DEFAULT_RSTYLE);
471 #endif
472 
473 		PVTS(r, page)->drawn_text[p] = NULL;
474 		PVTS(r, page)->drawn_rend[p] = NULL;
475 		rxvt_blank_screen_mem (r, page, PVTS(r, page)->drawn_text,
476 			PVTS(r, page)->drawn_rend, p, DEFAULT_RSTYLE);
477 	}
478 
479 	if (i > 0) {
480 		rxvt_scroll_text(r, page, 0, (int)nrow - 1, -i, 1);
481 		PSCR(r, page).cur.row += i;
482 		PSCR(r, page).s_cur.row += i;
483 		PVTS(r, page)->nscrolled -= i;
484 	}
485 
486 	assert(PSCR(r, page).cur.row < r->TermWin.nrow);
487 	MIN_IT(PSCR(r, page).cur.row, nrow - 1);
488 #if NSCREENS
489 	assert(PVTS(r, page)->swap.cur.row < r->TermWin.nrow);
490 	MIN_IT(PVTS(r, page)->swap.cur.row, nrow - 1);
491 #endif
492 }
493 
494 
495 
496 /* INTPROTO */
497 void
rxvt_scr_adjust_col(rxvt_t * r,int page,unsigned int total_rows)498 rxvt_scr_adjust_col (rxvt_t* r, int page, unsigned int total_rows)
499 {
500 	unsigned int	nrow, ncol, prev_ncol;
501 	unsigned int	p;
502 
503 
504 	nrow = r->TermWin.nrow;
505 	ncol = r->TermWin.ncol;
506 	prev_ncol = PVTS(r, page)->prev_ncol;
507 
508 	DBG_MSG(2, (stderr, "rxvt_scr_adjust_col %d (ncol=%d, prev_ncol = %d, nrow=%d, total_row=%d)\n", page, ncol, prev_ncol, nrow, total_rows));
509 
510 	for (p = 0; p < total_rows; p++) {
511 		if (PSCR(r, page).text[p]) {
512 			PSCR(r, page).text[p] = rxvt_realloc (
513 				PSCR(r, page).text[p], ncol * sizeof(text_t));
514 			PSCR(r, page).rend[p] = rxvt_realloc (
515 				PSCR(r, page).rend[p], ncol * sizeof(rend_t));
516 			MIN_IT(PSCR(r, page).tlen[p], (RINT16T)ncol);
517 			if (ncol > prev_ncol)
518 				rxvt_blank_line (
519 					&(PSCR(r, page).text[p][prev_ncol]),
520 					&(PSCR(r, page).rend[p][prev_ncol]),
521 					ncol - prev_ncol, DEFAULT_RSTYLE);
522 		}
523 	}
524 
525 	for (p = 0; p < nrow; p++) {
526 		PVTS(r, page)->drawn_text[p] = rxvt_realloc (
527 			PVTS(r, page)->drawn_text[p], ncol * sizeof(text_t));
528 		PVTS(r, page)->drawn_rend[p] = rxvt_realloc (
529 			PVTS(r, page)->drawn_rend[p], ncol * sizeof(rend_t));
530 #if NSCREENS
531 		if (PVTS(r, page)->swap.text[p]) {
532 			PVTS(r, page)->swap.text[p] = rxvt_realloc (
533 				PVTS(r, page)->swap.text[p], ncol * sizeof(text_t));
534 			PVTS(r, page)->swap.rend[p] = rxvt_realloc (
535 				PVTS(r, page)->swap.rend[p], ncol * sizeof(rend_t));
536 			MIN_IT(PVTS(r, page)->swap.tlen[p], (RINT16T)ncol);
537 			if (ncol > prev_ncol)
538 				rxvt_blank_line(
539 					&(PVTS(r, page)->swap.text[p][prev_ncol]),
540 					&(PVTS(r, page)->swap.rend[p][prev_ncol]),
541 					ncol - prev_ncol, DEFAULT_RSTYLE);
542 		}
543 #endif
544 		if (ncol > prev_ncol)
545 			rxvt_blank_line(
546 				&(PVTS(r, page)->drawn_text[p][prev_ncol]),
547 				&(PVTS(r, page)->drawn_rend[p][prev_ncol]),
548 				ncol - prev_ncol, DEFAULT_RSTYLE);
549 	}
550 	MIN_IT(PSCR(r, page).cur.col, (RINT16T)ncol - 1);
551 #if NSCREENS
552 	MIN_IT(PVTS(r, page)->swap.cur.col, (RINT16T)ncol - 1);
553 #endif
554 
555 
556 	/*
557 	** Only reset tabstop if expanding columns, save realloc in
558 	** shrinking columns
559 	*/
560 	if (r->tabstop && ncol > prev_ncol)	{
561 		DBG_MSG(1, (stderr, "expand r->tabstop to %d\n", ncol));
562 		r->tabstop = rxvt_realloc(r->tabstop, ncol * sizeof(char));
563 		for (p = prev_ncol; p < ncol; p++)
564 			r->tabstop[p] = (p % TABSTOP_SIZE == 0) ? 1 : 0;
565 	}
566 }
567 
568 
569 
570 /* EXTPROTO */
571 void
rxvt_scr_reset(rxvt_t * r,int page)572 rxvt_scr_reset(rxvt_t* r, int page)
573 {
574 	unsigned int	ncol, nrow, prev_ncol, prev_nrow,
575 					total_rows, prev_total_rows;
576 
577 
578 	DBG_MSG(1,(stderr, "rxvt_scr_reset %d ()\n", page));
579 
580 	PVTS(r, page)->view_start = 0;
581 	RESET_CHSTAT(r, page);
582 	PVTS(r, page)->num_scr = 0;	/* number of lines scrolled */
583 
584 	prev_ncol = PVTS(r, page)->prev_ncol;
585 	prev_nrow = PVTS(r, page)->prev_nrow;
586 	if (r->TermWin.ncol == 0)
587 		r->TermWin.ncol = 80;
588 	if (r->TermWin.nrow == 0)
589 		r->TermWin.nrow = 24;
590 	ncol = r->TermWin.ncol;
591 	nrow = r->TermWin.nrow;
592 	if (PVTS(r, page)->init_screen &&
593 		ncol == prev_ncol && nrow == prev_nrow)
594 		return;
595 
596 	DBG_MSG(1,(stderr, "rxvt_scr_reset %d () refresh screen\n", page));
597 	r->h->want_refresh = 1;
598 
599 	total_rows = nrow + SVLINES;
600 	prev_total_rows = prev_nrow + SVLINES;
601 
602 	PSCR(r, page).tscroll = 0;
603 	PSCR(r, page).bscroll = nrow - 1;
604 
605 	if (PVTS(r, page)->init_screen == 0) {
606 		/* Initialize the screen structures */
607 		rxvt_scr_alloc (r, page);
608 	}
609 	else {
610 		/* B1: resize rows */
611 		if (nrow < prev_nrow) {
612 			rxvt_scr_delete_row (r, page);
613 		}
614 		else if (nrow > prev_nrow) {
615 			rxvt_scr_add_row (r, page, total_rows, prev_total_rows);
616 		}
617 		/* B2: resize columns */
618 		if (ncol != prev_ncol) {
619 			rxvt_scr_adjust_col (r, page, total_rows);
620 		}
621 	}
622 
623 	PVTS(r, page)->prev_nrow = nrow;
624 	PVTS(r, page)->prev_ncol = ncol;
625 
626 	rxvt_tt_winsize(PVTS(r, page)->cmd_fd, r->TermWin.ncol, r->TermWin.nrow, PVTS(r, page)->cmd_pid);
627 }
628 
629 
630 
631 
632 /* ------------------------------------------------------------------------- */
633 /*
634  * Free everything.  That way malloc debugging can find leakage.
635  */
636 /* EXTPROTO */
637 void
rxvt_scr_release(rxvt_t * r,int page)638 rxvt_scr_release(rxvt_t* r, int page)
639 {
640 	unsigned int	total_rows;
641 	int				i;
642 
643 
644 	DBG_MSG(1, (stderr, "rxvt_scr_release %d ()\n", page));
645 	total_rows = r->TermWin.nrow + SVLINES;
646 
647 	for (i = 0; i < total_rows; i++) {
648 		if (PSCR(r, page).text[i]) {
649 			/* then so is PSCR(r, page).rend[i] */
650 			free(PSCR(r, page).text[i]);
651 			PSCR(r, page).text[i] = NULL;
652 			assert(PSCR(r, page).rend[i]);
653 			free(PSCR(r, page).rend[i]);
654 			PSCR(r, page).rend[i] = NULL;
655 		}
656 	}
657 
658 	for (i = 0; i < r->TermWin.nrow; i++) {
659 		// if (PVTS(r, page)->drawn_text[i])
660 			free(PVTS(r, page)->drawn_text[i]);
661 		PVTS(r, page)->drawn_text[i] = NULL;
662 		// if (PVTS(r, page)->drawn_rend[i])
663 			free(PVTS(r, page)->drawn_rend[i]);
664 		PVTS(r, page)->drawn_rend[i] = NULL;
665 #if NSCREENS
666 		// if (PVTS(r, page)->swap.text[i])
667 			free(PVTS(r, page)->swap.text[i]);
668 		PVTS(r, page)->swap.text[i] = NULL;
669 		// if (PVTS(r, page)->swap.rend[i]))
670 			free(PVTS(r, page)->swap.rend[i]);
671 		PVTS(r, page)->swap.rend[i] = NULL;
672 #endif
673 	}
674 
675 	free(PSCR(r, page).text); PSCR(r, page).text = NULL;
676 	free(PSCR(r, page).tlen); PSCR(r, page).tlen = NULL;
677 	free(PSCR(r, page).rend); PSCR(r, page).rend = NULL;
678 	free(PVTS(r, page)->drawn_text);  PVTS(r, page)->drawn_text = NULL;
679 	free(PVTS(r, page)->drawn_rend);  PVTS(r, page)->drawn_rend = NULL;
680 #if NSCREENS
681 	free(PVTS(r, page)->swap.text);   PVTS(r, page)->swap.text = NULL;
682 	free(PVTS(r, page)->swap.tlen);   PVTS(r, page)->swap.tlen = NULL;
683 	free(PVTS(r, page)->swap.rend);   PVTS(r, page)->swap.rend = NULL;
684 #endif
685 	free(PVTS(r, page)->buf_text);	PVTS(r, page)->buf_text = NULL;
686 	free(PVTS(r, page)->buf_rend);	PVTS(r, page)->buf_rend = NULL;
687 
688 	/* next rxvt_scr_reset will be the first time initialization */
689 	PVTS(r, page)->init_screen = 0;
690 
691 	/* clear selection if necessary */
692 	if (page == r->selection.vt)	{
693 		rxvt_process_selectionclear (r, page);
694 	}
695 }
696 
697 /* ------------------------------------------------------------------------- */
698 /*
699  * Hard reset
700  */
701 /* EXTPROTO */
702 void
rxvt_scr_poweron(rxvt_t * r,int page)703 rxvt_scr_poweron(rxvt_t* r, int page)
704 {
705 	DBG_MSG(1,(stderr, "rxvt_scr_poweron %d ()\n", page));
706 
707 	rxvt_scr_release(r, page);
708 	PVTS(r, page)->prev_nrow = PVTS(r, page)->prev_ncol = 0;
709 	rxvt_scr_reset(r, page);
710 
711 	rxvt_scr_clear(r, page);
712 	rxvt_scr_refresh(r, page, SLOW_REFRESH);
713 }
714 
715 
716 /* ------------------------------------------------------------------------- *
717  *						 PROCESS SCREEN COMMANDS						   *
718  * ------------------------------------------------------------------------- */
719 /*
720  * Save and Restore cursor
721  * XTERM_SEQ: Save cursor   : ESC 7
722  * XTERM_SEQ: Restore cursor: ESC 8
723  */
724 /* EXTPROTO */
725 void
rxvt_scr_cursor(rxvt_t * r,int page,int mode)726 rxvt_scr_cursor(rxvt_t* r, int page, int mode)
727 {
728 	screen_t	   *s;
729 
730 	DBG_MSG(2,(stderr, "rxvt_scr_cursor %d (%c)\n", page, mode));
731 
732 #if NSCREENS && !defined(NO_SECONDARY_SCREEN_CURSOR)
733 	if (PVTS(r, page)->current_screen == SECONDARY)
734 		s = &(PVTS(r, page)->swap);
735 	else
736 #endif
737 	s = &(PSCR(r, page));
738 	switch (mode) {
739 	case SAVE:
740 		s->s_cur.row = s->cur.row;
741 		s->s_cur.col = s->cur.col;
742 		s->s_rstyle = PVTS(r, page)->rstyle;
743 		s->s_charset = s->charset;
744 		s->s_charset_char = PVTS(r, page)->charsets[s->charset];
745 		break;
746 	case RESTORE:
747 		r->h->want_refresh = 1;
748 		s->cur.row = s->s_cur.row;
749 		s->cur.col = s->s_cur.col;
750 		s->flags &= ~Screen_WrapNext;
751 		PVTS(r, page)->rstyle = s->s_rstyle;
752 		s->charset = s->s_charset;
753 		PVTS(r, page)->charsets[s->charset] = s->s_charset_char;
754 		rxvt_set_font_style(r, page);
755 		break;
756 	}
757 /* boundary check in case screen size changed between SAVE and RESTORE */
758 	MIN_IT(s->cur.row, r->TermWin.nrow - 1);
759 	MIN_IT(s->cur.col, r->TermWin.ncol - 1);
760 	assert(s->cur.row >= 0);
761 	assert(s->cur.col >= 0);
762 	MAX_IT(s->cur.row, 0);
763 	MAX_IT(s->cur.col, 0);
764 }
765 
766 /* ------------------------------------------------------------------------- */
767 /*
768  * Swap between primary and secondary screens
769  * XTERM_SEQ: Primary screen  : ESC [ ? 4 7 h
770  * XTERM_SEQ: Secondary screen: ESC [ ? 4 7 l
771  */
772 /* EXTPROTO */
773 int
rxvt_scr_change_screen(rxvt_t * r,int page,int scrn)774 rxvt_scr_change_screen(rxvt_t* r, int page, int scrn)
775 {
776 #if NSCREENS
777 	unsigned int		i, offset;
778 #endif
779 
780 	r->h->want_refresh = 1;
781 
782 	DBG_MSG(1,(stderr, "rxvt_scr_change_screen %d (%d)\n", page, scrn));
783 
784 	VSTART = 0;
785 	RESET_CHSTAT(r, page);
786 
787 	if (PVTS(r, page)->current_screen == scrn)
788 		return PVTS(r, page)->current_screen;
789 
790 	rxvt_selection_check(r, page, 2);	/* check for boundary cross */
791 
792 	SWAP_IT(PVTS(r, page)->current_screen, scrn, int);
793 
794 #if NSCREENS
795 	PVTS(r, page)->num_scr = 0;
796 	offset = SVLINES;
797 
798 	for (i = PVTS(r, page)->prev_nrow; i--;) {
799 		SWAP_IT(PSCR(r, page).text[i + offset],
800 			PVTS(r, page)->swap.text[i], text_t *);
801 		SWAP_IT(PSCR(r, page).tlen[i + offset],
802 			PVTS(r, page)->swap.tlen[i], RINT16T);
803 		SWAP_IT(PSCR(r, page).rend[i + offset],
804 			PVTS(r, page)->swap.rend[i], rend_t *);
805 	}
806 	SWAP_IT(CURROW, PVTS(r, page)->swap.cur.row, RINT16T);
807 	SWAP_IT(CURCOL, PVTS(r, page)->swap.cur.col, RINT16T);
808 	assert (CURROW >= 0);
809 	assert (CURROW < PVTS(r, page)->prev_nrow);
810 	assert (CURCOL >= 0);
811 	assert (CURCOL < PVTS(r, page)->prev_ncol);
812 	MAX_IT(CURROW, 0);
813 	MIN_IT(CURROW, (RINT32T)PVTS(r, page)->prev_nrow - 1);
814 	MAX_IT(CURCOL, 0);
815 	MIN_IT(CURCOL, (RINT32T)PVTS(r, page)->prev_ncol - 1);
816 
817 	SWAP_IT(PSCR(r, page).charset, PVTS(r, page)->swap.charset,
818 		RINT16T);
819 	SWAP_IT(PSCR(r, page).flags, PVTS(r, page)->swap.flags, int);
820 	PSCR(r, page).flags |= Screen_VisibleCursor;
821 	PVTS(r, page)->swap.flags |= Screen_VisibleCursor;
822 
823 #else
824 # ifdef SCROLL_ON_NO_SECONDARY
825 	if (PVTS(r, page)->current_screen == PRIMARY)
826 		rxvt_scroll_text(r, page, 0, (PVTS(r, page)->prev_nrow - 1),
827 			PVTS(r, page)->prev_nrow, 0);
828 # endif
829 #endif
830 
831 	/* Need to update tabbar buttons */
832 	if (r->Options2 & Opt2_protectSecondary)
833 		rxvt_tabbar_draw_buttons (r);
834 
835 	return scrn;
836 }
837 
838 /* ------------------------------------------------------------------------- */
839 /*
840  * Change the colour for following text
841  */
842 /* EXTPROTO */
843 void
rxvt_scr_color(rxvt_t * r,int page,unsigned int color,int fgbg)844 rxvt_scr_color(rxvt_t* r, int page, unsigned int color, int fgbg)
845 {
846 	color &= RS_fgMask;
847 	if (Color_fg == fgbg)
848 		PVTS(r, page)->rstyle=SET_FGCOLOR(PVTS(r, page)->rstyle, color);
849 	else
850 		PVTS(r, page)->rstyle=SET_BGCOLOR(PVTS(r, page)->rstyle, color);
851 }
852 
853 
854 /* ------------------------------------------------------------------------- */
855 /*
856  * Change the rendition style for following text
857  */
858 /* EXTPROTO */
859 void
rxvt_scr_rendition(rxvt_t * r,int page,int set,int style)860 rxvt_scr_rendition(rxvt_t* r, int page, int set, int style)
861 {
862 	if (set)
863 		PVTS(r, page)->rstyle |= style;
864 	else if (style == ~RS_None)
865 		PVTS(r, page)->rstyle = DEFAULT_RSTYLE | (PVTS(r, page)->rstyle & RS_fontMask);
866 	else
867 		PVTS(r, page)->rstyle &= ~style;
868 }
869 
870 /* ------------------------------------------------------------------------- */
871 /*
872  * Scroll text between <row1> and <row2> inclusive, by <count> lines
873  * count positive ==> scroll up
874  * count negative ==> scroll down
875  * spec == 0 for normal routines
876  */
877 /* EXTPROTO */
878 int
rxvt_scroll_text(rxvt_t * r,int page,int row1,int row2,int count,int spec)879 rxvt_scroll_text(rxvt_t* r, int page, int row1, int row2, int count, int spec)
880 {
881 	int				i, j;
882 	unsigned int	nscrolled;
883 
884 	if (count == 0 || (row1 > row2))
885 		return 0;
886 
887 	r->h->want_refresh = 1;
888 	DBG_MSG(2,(stderr, "rxvt_scroll_text %d (%d,%d,%d,%d): %s\n", page, row1, row2, count, spec, (PVTS(r, page)->current_screen == PRIMARY) ? "Primary" : "Secondary"));
889 
890 	if ((count > 0) &&
891 		(row1 == 0) &&
892 		(PVTS(r, page)->current_screen == PRIMARY)) {
893 		nscrolled = (unsigned int)PVTS(r, page)->nscrolled + (unsigned int)count;;
894 		if (nscrolled > (unsigned int)SVLINES)
895 			PVTS(r, page)->nscrolled = SVLINES;
896 		else
897 			PVTS(r, page)->nscrolled = (RUINT16T)nscrolled;
898 		if ((r->Options & Opt_scrollWithBuffer) &&
899 			VSTART != 0 &&
900 			VSTART != SVLINES)
901 			rxvt_scr_page(r, page, UP, count);
902 	}
903 	else if (!spec)
904 		row1 += SVLINES;
905 	row2 += SVLINES;
906 
907 	if (SEL(r).op &&
908 		SEL(r).vt == page &&
909 		PVTS(r, page)->current_screen == SEL(r).screen) {
910 		i = SEL(r).beg.row + SVLINES;
911 		j = SEL(r).end.row + SVLINES;
912 		if ((i < row1 && j > row1) ||
913 			(i < row2 && j > row2) ||
914 			(i - count < row1 && i >= row1) ||
915 			(i - count > row2 && i <= row2) ||
916 			(j - count < row1 && j >= row1) ||
917 			(j - count > row2 && j <= row2)) {
918 			CLEAR_ALL_SELECTION(r);
919 			/* XXX: too aggressive? */
920 			SEL(r).op = SELECTION_CLEAR;
921 		}
922 		else if (j >= row1 && j <= row2) {
923 			/* move selected region too */
924 			SEL(r).beg.row -= count;
925 			SEL(r).end.row -= count;
926 			SEL(r).mark.row -= count;
927 		}
928 	}
929 
930 	/* _after_ PVTS(r, page)->nscrolled update */
931 	rxvt_selection_check(r, page, 0);
932 
933 	PVTS(r, page)->num_scr += count;
934 	j = count;
935 	if (count < 0)
936 		count = -count;
937 	i = row2 - row1 + 1;
938 	MIN_IT(count, i);
939 
940 	if (j > 0) {
941 /* A: scroll up */
942 
943 /* A1: Copy lines that will get clobbered by the rotation */
944 		for (i = 0, j = row1; i < count; i++, j++) {
945 			PVTS(r, page)->buf_text[i] = PSCR(r, page).text[j];
946 			PVTS(r, page)->buf_rend[i] = PSCR(r, page).rend[j];
947 		}
948 /* A2: Rotate lines */
949 		for (j = row1, i = j + count; i <= row2; i++, j++) {
950 			PSCR(r, page).tlen[j] = PSCR(r, page).tlen[i];
951 			PSCR(r, page).text[j] = PSCR(r, page).text[i];
952 			PSCR(r, page).rend[j] = PSCR(r, page).rend[i];
953 		}
954 		j = row2 - count + 1, i = count;
955 	}
956 	else /* if (j < 0) */ {
957 /* B: scroll down */
958 
959 /* B1: Copy lines that will get clobbered by the rotation */
960 		for (i = 0, j = row2; i < count; i++, j--) {
961 			PVTS(r, page)->buf_text[i] = PSCR(r, page).text[j];
962 			PVTS(r, page)->buf_rend[i] = PSCR(r, page).rend[j];
963 		}
964 /* B2: Rotate lines */
965 		for (j = row2, i = j - count; i >= row1; i--, j--) {
966 			PSCR(r, page).tlen[j] = PSCR(r, page).tlen[i];
967 			PSCR(r, page).text[j] = PSCR(r, page).text[i];
968 			PSCR(r, page).rend[j] = PSCR(r, page).rend[i];
969 		}
970 		j = row1, i = count;
971 		count = -count;
972 	}
973 
974 /* C: Resurrect lines */
975 	for (; i--; j++) {
976 		PSCR(r, page).tlen[j] = 0;
977 		PSCR(r, page).text[j] = PVTS(r, page)->buf_text[i];
978 		PSCR(r, page).rend[j] = PVTS(r, page)->buf_rend[i];
979 		if (!spec)		/* line length may not equal TermWin.ncol */
980 			rxvt_blank_screen_mem(r, page, PSCR(r, page).text,
981 				PSCR(r, page).rend, (unsigned int)j,
982 				PVTS(r, page)->rstyle);
983 	}
984 
985 	return count;
986 }
987 
988 /* ------------------------------------------------------------------------- */
989 /*
990  * Add text given in <str> of length <len> to screen struct
991  */
992 /* EXTPROTO */
993 void
rxvt_scr_add_lines(rxvt_t * r,int page,const unsigned char * str,int nlines,int len)994 rxvt_scr_add_lines(rxvt_t* r, int page, const unsigned char *str, int nlines, int len)
995 {
996 	unsigned char   checksel, clearsel;
997 	char			c;
998 	int			 i, row, last_col;
999 	text_t		 *stp;
1000 	rend_t		 *srp;
1001 	struct rxvt_hidden *h = r->h;
1002 
1003 	if (len <= 0)		/* sanity */
1004 	return;
1005 
1006 	h->want_refresh = 1;
1007 	last_col = r->TermWin.ncol;
1008 
1009 	DBG_MSG(2,(stderr, "rxvt_scr_add_lines %d (%d,%d)\n", page, nlines, len));
1010 	ZERO_SCROLLBACK(r, page);
1011 	if (nlines > 0) {
1012 		nlines += (CURROW - PSCR(r, page).bscroll);
1013 		if ((nlines > 0) &&
1014 			(PSCR(r, page).tscroll == 0) &&
1015 			(PSCR(r, page).bscroll == (r->TermWin.nrow - 1))) {
1016 			/* _at least_ this many lines need to be scrolled */
1017 			rxvt_scroll_text(r, page, PSCR(r, page).tscroll,
1018 				PSCR(r, page).bscroll, nlines, 0);
1019 			CURROW -= nlines;
1020 		}
1021 	}
1022 
1023 	assert(CURCOL < last_col);
1024 	assert((CURROW < r->TermWin.nrow) &&
1025 		(CURROW >= -(RINT32T)PVTS(r, page)->nscrolled));
1026 	MIN_IT(CURCOL, last_col - 1);
1027 	MIN_IT(CURROW, (RINT32T)r->TermWin.nrow - 1);
1028 	MAX_IT(CURROW, -(RINT32T)PVTS(r, page)->nscrolled);
1029 
1030 	row = CURROW + SVLINES;
1031 
1032 	checksel = (SEL(r).op && SEL(r).vt == page &&
1033 		PVTS(r, page)->current_screen == SEL(r).screen) ? 1 : 0;
1034 	clearsel = 0;
1035 
1036 	stp = PSCR(r, page).text[row];
1037 	srp = PSCR(r, page).rend[row];
1038 
1039 #ifdef MULTICHAR_SET
1040 	if (PVTS(r, page)->lost_multi &&
1041 		CURCOL > 0 &&
1042 		IS_MULTI1(srp[CURCOL - 1]) &&
1043 		*str != '\n' && *str != '\r' && *str != '\t')
1044 		PVTS(r, page)->chstat = WBYTE;
1045 #endif
1046 
1047 	for (i = 0; i < len;) {
1048 		c = str[i++];
1049 		switch (c) {
1050 		case '\t':
1051 			rxvt_scr_tab(r, page, 1);
1052 			continue;
1053 
1054 		case '\n':
1055 			/* XXX: think about this */
1056 			if (PSCR(r, page).tlen[row] != -1)
1057 				MAX_IT(PSCR(r, page).tlen[row], CURCOL);
1058 				PSCR(r, page).flags &= ~Screen_WrapNext;
1059 				if (CURROW == PSCR(r, page).bscroll)
1060 					rxvt_scroll_text(r, page, PSCR(r, page).tscroll,
1061 						PSCR(r, page).bscroll, 1, 0);
1062 				else if (CURROW < (r->TermWin.nrow - 1))
1063 					row = (++CURROW) + SVLINES;
1064 				stp = PSCR(r, page).text[row];	/* _must_ refresh */
1065 				srp = PSCR(r, page).rend[row];	/* _must_ refresh */
1066 				RESET_CHSTAT(r, page);
1067 				continue;
1068 
1069 		case '\r':
1070 			/* XXX: think about this */
1071 			if (PSCR(r, page).tlen[row] != -1)
1072 				MAX_IT(PSCR(r, page).tlen[row], CURCOL);
1073 			PSCR(r, page).flags &= ~Screen_WrapNext;
1074 			CURCOL = 0;
1075 			RESET_CHSTAT(r, page);
1076 			continue;
1077 
1078 		default:
1079 #ifdef MULTICHAR_SET
1080 			if (r->encoding_method == ENC_NOENC) {
1081 				if (c == 127)
1082 					continue;
1083 				break;
1084 			}
1085 			PVTS(r, page)->rstyle &= ~RS_multiMask;
1086 
1087 			/* multibyte 2nd byte */
1088 			if (PVTS(r, page)->chstat == WBYTE) {
1089 				/* set flag of second byte in style */
1090 				PVTS(r, page)->rstyle |= RS_multi2;
1091 				/* switch back to single byte for next char */
1092 				PVTS(r, page)->chstat = SBYTE;
1093 				if ((r->encoding_method == ENC_EUCJ) &&
1094 					((char) stp[CURCOL-1] == (char) 0x8e))	{
1095 					PVTS(r, page)->rstyle &= ~RS_multiMask;
1096 					CURCOL --;
1097 				}
1098 				else
1099 				/* maybe overkill, but makes it selectable */
1100 				if ((r->encoding_method == ENC_EUCJ) ||
1101 					(r->encoding_method == ENC_GBK) ||
1102 					(r->encoding_method == ENC_GB))
1103 					c |= 0x80;
1104 			}
1105 			/* multibyte 1st byte */
1106 			else if (PVTS(r, page)->chstat == SBYTE) {
1107 				if (r->encoding_method == ENC_SJIS)	{
1108 					if (PVTS(r, page)->multi_byte ||
1109 						(((unsigned char) c >= (unsigned char) 0x81 &&
1110 						  (unsigned char) c <= (unsigned char) 0x9f) ||
1111 						 ((unsigned char) c >= (unsigned char) 0xe0 &&
1112 						  (unsigned char) c <= (unsigned char) 0xfc))
1113 						)	{
1114 						PVTS(r, page)->rstyle |= RS_multi1;
1115 						PVTS(r, page)->chstat = WBYTE;
1116 					}
1117 				}
1118 				else
1119 				if (PVTS(r, page)->multi_byte || (c & 0x80)) {
1120 					/* set flag of first byte in style */
1121 					PVTS(r, page)->rstyle |= RS_multi1;
1122 					/* switch to multiple byte for next char */
1123 					PVTS(r, page)->chstat = WBYTE;
1124 					/* maybe overkill, but makes selectable */
1125 					if ((r->encoding_method == ENC_EUCJ) ||
1126 						(r->encoding_method == ENC_GBK) ||
1127 						(r->encoding_method == ENC_GB))
1128 						c |= 0x80;
1129 				}
1130 			}
1131 			else
1132 #endif
1133 			if (c == 127)
1134 				continue;	/* yummmm..... */
1135 			break;
1136 		}	/* switch */
1137 
1138 		if (checksel &&		/* see if we're writing within selection */
1139 			!RC_BEFORE(PSCR(r, page).cur, SEL(r).beg) &&
1140 			RC_BEFORE(PSCR(r, page).cur, SEL(r).end)) {
1141 			checksel = 0;
1142 			clearsel = 1;
1143 		}
1144 
1145 		if (PSCR(r, page).flags & Screen_WrapNext) {
1146 			PSCR(r, page).tlen[row] = -1;
1147 			if (CURROW == PSCR(r, page).bscroll)
1148 				rxvt_scroll_text(r, page, PSCR(r, page).tscroll,
1149 					PSCR(r, page).bscroll, 1, 0);
1150 			else if (CURROW < (r->TermWin.nrow - 1))
1151 				row = (++CURROW) + SVLINES;
1152 			stp = PSCR(r, page).text[row];	/* _must_ refresh */
1153 			srp = PSCR(r, page).rend[row];	/* _must_ refresh */
1154 			CURCOL = 0;
1155 			PSCR(r, page).flags &= ~Screen_WrapNext;
1156 		}
1157 
1158 		if (PSCR(r, page).flags & Screen_Insert)
1159 			rxvt_scr_insdel_chars(r, page, 1, INSERT);
1160 
1161 #ifdef MULTICHAR_SET
1162 		if (IS_MULTI1(PVTS(r, page)->rstyle) &&
1163 			CURCOL > 0 &&
1164 			IS_MULTI1(srp[CURCOL - 1])) {
1165 			stp[CURCOL - 1] = ' ';
1166 			srp[CURCOL - 1] &= ~RS_multiMask;
1167 		}
1168 		else if (IS_MULTI2(PVTS(r, page)->rstyle) &&
1169 			CURCOL < (last_col - 1) &&
1170 			IS_MULTI2(srp[CURCOL + 1])) {
1171 			stp[CURCOL + 1] = ' ';
1172 			srp[CURCOL + 1] &= ~RS_multiMask;
1173 		}
1174 #endif
1175 
1176 		stp[CURCOL] = c;
1177 		srp[CURCOL] = PVTS(r, page)->rstyle;
1178 		if (CURCOL < (last_col - 1))
1179 			CURCOL++;
1180 		else {
1181 			PSCR(r, page).tlen[row] = last_col;
1182 			if (PSCR(r, page).flags & Screen_Autowrap)
1183 				PSCR(r, page).flags |= Screen_WrapNext;
1184 		}
1185 	}	/* for */
1186 
1187 	if (PSCR(r, page).tlen[row] != -1)	/* XXX: think about this */
1188 		MAX_IT(PSCR(r, page).tlen[row], CURCOL);
1189 
1190 	/*
1191 	** If we wrote anywhere in the selected area, kill the selection
1192 	** XXX: should we kill the mark too?  Possibly, but maybe that
1193 	**	  should be a similar check.
1194 	*/
1195 	if (clearsel)
1196 		CLEAR_SELECTION(r);
1197 
1198 	assert(CURROW >= 0);
1199 	MAX_IT(CURROW, 0);
1200 }
1201 
1202 /* ------------------------------------------------------------------------- */
1203 /*
1204  * Process Backspace.  Move back the cursor back a position, wrap if have to
1205  * XTERM_SEQ: CTRL-H
1206  */
1207 /* EXTPROTO */
1208 void
rxvt_scr_backspace(rxvt_t * r,int page)1209 rxvt_scr_backspace(rxvt_t* r, int page)
1210 {
1211 	RESET_CHSTAT(r, page);
1212 	r->h->want_refresh = 1;
1213 	if (CURCOL == 0) {
1214 		if (CURROW > 0) {
1215 #ifdef TERMCAP_HAS_BW
1216 			CURCOL = r->TermWin.ncol - 1;
1217 			CURROW--;
1218 			return;
1219 #endif
1220 		}
1221 	} else if ((PSCR(r, page).flags & Screen_WrapNext) == 0)
1222 		rxvt_scr_gotorc(r, page, 0, -1, RELATIVE);
1223 	PSCR(r, page).flags &= ~Screen_WrapNext;
1224 }
1225 
1226 /* ------------------------------------------------------------------------- */
1227 /*
1228  * Process Horizontal Tab
1229  * count: +ve = forward; -ve = backwards
1230  * XTERM_SEQ: CTRL-I
1231  */
1232 /* EXTPROTO */
1233 void
rxvt_scr_tab(rxvt_t * r,int page,int count)1234 rxvt_scr_tab(rxvt_t* r, int page, int count)
1235 {
1236 	int			 i, x;
1237 
1238 	DBG_MSG(3,(stderr, "rxvt_scr_tab %d (%d)\n", page, count));
1239 	r->h->want_refresh = 1;
1240 	RESET_CHSTAT(r, page);
1241 	i = x = CURCOL;
1242 	if (count == 0)
1243 		return;
1244 	else if (count > 0) {
1245 		for (; ++i < r->TermWin.ncol; )
1246 			if (r->tabstop[i]) {
1247 				x = i;
1248 			if (!--count)
1249 				break;
1250 		}
1251 		if (count)
1252 			x = r->TermWin.ncol - 1;
1253 	}
1254 	else /* if (count < 0) */ {
1255 		for (; --i >= 0; )
1256 			if (r->tabstop[i]) {
1257 				x = i;
1258 				if (!++count)
1259 					break;
1260 			}
1261 		if (count)
1262 			x = 0;
1263 	}
1264 	if (x != CURCOL)
1265 		rxvt_scr_gotorc(r, page, 0, x, R_RELATIVE);
1266 }
1267 
1268 /* ------------------------------------------------------------------------- */
1269 /*
1270  * Process DEC Back Index
1271  * XTERM_SEQ: ESC 6
1272  * Move cursor left in row.  If we're at the left boundary, shift everything
1273  * in that row right.  Clear left column.
1274  */
1275 #ifndef NO_FRILLS
1276 /* EXTPROTO */
1277 void
rxvt_scr_backindex(rxvt_t * r,int page)1278 rxvt_scr_backindex(rxvt_t* r, int page)
1279 {
1280 	if (CURCOL > 0)
1281 		rxvt_scr_gotorc(r, page, 0, -1, R_RELATIVE | C_RELATIVE);
1282 	else {
1283 		if (PSCR(r, page).tlen[CURROW + SVLINES] == 0)
1284 			return;		/* um, yeah? */
1285 		rxvt_scr_insdel_chars(r, page, 1, INSERT);
1286 	}
1287 }
1288 #endif
1289 /* ------------------------------------------------------------------------- */
1290 /*
1291  * Process DEC Forward Index
1292  * XTERM_SEQ: ESC 9
1293  * Move cursor right in row.  If we're at the right boundary, shift everything
1294  * in that row left.  Clear right column.
1295  */
1296 #ifndef NO_FRILLS
1297 /* EXTPROTO */
1298 void
rxvt_scr_forwardindex(rxvt_t * r,int page)1299 rxvt_scr_forwardindex(rxvt_t* r, int page)
1300 {
1301 	int			 row;
1302 
1303 	if (CURCOL < r->TermWin.ncol - 1)
1304 		rxvt_scr_gotorc(r, page, 0, 1, R_RELATIVE | C_RELATIVE);
1305 	else {
1306 		row = CURROW + SVLINES;
1307 		if (PSCR(r, page).tlen[row] == 0)
1308 			return;		/* um, yeah? */
1309 		else if (PSCR(r, page).tlen[row] == -1)
1310 			PSCR(r, page).tlen[row] = r->TermWin.ncol;
1311 		rxvt_scr_gotorc(r, page, 0, 0, R_RELATIVE);
1312 		rxvt_scr_insdel_chars(r, page, 1, DELETE);
1313 		rxvt_scr_gotorc(r, 0, page, r->TermWin.ncol - 1, R_RELATIVE);
1314 	}
1315 }
1316 #endif
1317 
1318 /* ------------------------------------------------------------------------- */
1319 /*
1320  * Goto Row/Column
1321  */
1322 /* EXTPROTO */
1323 void
rxvt_scr_gotorc(rxvt_t * r,int page,int row,int col,int relative)1324 rxvt_scr_gotorc(rxvt_t* r, int page, int row, int col, int relative)
1325 {
1326 	r->h->want_refresh = 1;
1327 	ZERO_SCROLLBACK(r, page);
1328 	RESET_CHSTAT(r, page);
1329 
1330 	DBG_MSG(2,(stderr, "rxvt_scr_gotorc %d (r:%s%d,c:%s%d): from (r:%d,c:%d)\n", page, (relative & R_RELATIVE ? "+" : ""), row, (relative & C_RELATIVE ? "+" : ""), col, CURROW, CURCOL));
1331 
1332 	CURCOL = ((relative & C_RELATIVE) ? (CURCOL + col)
1333 						 : col);
1334 	MAX_IT(CURCOL, 0);
1335 	MIN_IT(CURCOL, (RINT32T)r->TermWin.ncol - 1);
1336 
1337 	PSCR(r, page).flags &= ~Screen_WrapNext;
1338 	if (relative & R_RELATIVE) {
1339 		if (row > 0) {
1340 			if (CURROW <= PSCR(r, page).bscroll &&
1341 				(CURROW + row) > PSCR(r, page).bscroll)
1342 				CURROW = PSCR(r, page).bscroll;
1343 			else
1344 				CURROW += row;
1345 		} else if (row < 0) {
1346 			if (CURROW >= PSCR(r, page).tscroll &&
1347 				(CURROW + row) < PSCR(r, page).tscroll)
1348 				CURROW = PSCR(r, page).tscroll;
1349 			else
1350 				CURROW += row;
1351 		}
1352 	}
1353 	else {
1354 		if (PSCR(r, page).flags & Screen_Relative) {
1355 			/* relative origin mode */
1356 			CURROW = row + PSCR(r, page).tscroll;
1357 			MIN_IT(CURROW, PSCR(r, page).bscroll);
1358 		}
1359 		else
1360 			CURROW = row;
1361 	}
1362 	MAX_IT(CURROW, 0);
1363 	MIN_IT(CURROW, (RINT32T)r->TermWin.nrow - 1);
1364 }
1365 
1366 /* ------------------------------------------------------------------------- */
1367 /*
1368  * direction  should be UP or DN
1369  */
1370 /* EXTPROTO */
1371 void
rxvt_scr_index(rxvt_t * r,int page,enum page_dirn direction)1372 rxvt_scr_index(rxvt_t* r, int page, enum page_dirn direction)
1373 {
1374 	int			 dirn;
1375 
1376 	r->h->want_refresh = 1;
1377 	dirn = ((direction == UP) ? 1 : -1);
1378 	DBG_MSG(1,(stderr, "rxvt_scr_index %d (%d)\n", page, dirn));
1379 
1380 	ZERO_SCROLLBACK(r, page);
1381 	RESET_CHSTAT(r, page);
1382 
1383 	PSCR(r, page).flags &= ~Screen_WrapNext;
1384 	if ((CURROW == PSCR(r, page).bscroll && direction == UP) ||
1385 		(CURROW == PSCR(r, page).tscroll && direction == DN))
1386 		rxvt_scroll_text(r, page, PSCR(r, page).tscroll, PSCR(r, page).bscroll, dirn, 0);
1387 	else
1388 		CURROW += dirn;
1389 	MAX_IT(CURROW, 0);
1390 	MIN_IT(CURROW, (RINT32T)r->TermWin.nrow - 1);
1391 	rxvt_selection_check(r, page, 0);
1392 }
1393 
1394 /* ------------------------------------------------------------------------- */
1395 /*
1396  * Erase part or whole of a line
1397  * XTERM_SEQ: Clear line to right: ESC [ 0 K
1398  * XTERM_SEQ: Clear line to left : ESC [ 1 K
1399  * XTERM_SEQ: Clear whole line   : ESC [ 2 K
1400  */
1401 /* EXTPROTO */
1402 void
rxvt_scr_erase_line(rxvt_t * r,int page,int mode)1403 rxvt_scr_erase_line(rxvt_t* r, int page, int mode)
1404 {
1405 	unsigned int	row, col, num;
1406 
1407 	r->h->want_refresh = 1;
1408 	DBG_MSG(2,(stderr, "rxvt_scr_erase_line %d (%d) at screen row: %d\n", page, mode, CURROW));
1409 	ZERO_SCROLLBACK(r, page);
1410 	RESET_CHSTAT(r, page);
1411 	rxvt_selection_check(r, page, 1);
1412 
1413 	PSCR(r, page).flags &= ~Screen_WrapNext;
1414 
1415 	row = SVLINES + CURROW;
1416 	switch (mode) {
1417 	case 0:			/* erase to end of line */
1418 		col = CURCOL;
1419 		num = r->TermWin.ncol - col;
1420 		MIN_IT(PSCR(r, page).tlen[row], (RINT16T)col);
1421 		if (RC_ROW_ATAFTER(SEL(r).beg, PSCR(r, page).cur) ||
1422 			RC_ROW_ATAFTER(SEL(r).end, PSCR(r, page).cur))
1423 			CLEAR_SELECTION(r);
1424 		break;
1425 	case 1:			/* erase to beginning of line */
1426 		col = 0;
1427 		num = CURCOL + 1;
1428 		if (RC_ROW_ATBEFORE(SEL(r).beg, PSCR(r, page).cur) ||
1429 			RC_ROW_ATBEFORE(SEL(r).end, PSCR(r, page).cur))
1430 			CLEAR_SELECTION(r);
1431 		break;
1432 	case 2:			/* erase whole line */
1433 		col = 0;
1434 		num = r->TermWin.ncol;
1435 		PSCR(r, page).tlen[row] = 0;
1436 		if (SEL(r).beg.row <= CURROW && SEL(r).end.row >= CURROW)
1437 			CLEAR_SELECTION(r);
1438 		break;
1439 	default:
1440 		return;
1441 	}
1442 
1443 	if (PSCR(r, page).text[row])
1444 		rxvt_blank_line(&(PSCR(r, page).text[row][col]),
1445 			&(PSCR(r, page).rend[row][col]), num, PVTS(r, page)->rstyle);
1446 	else
1447 		rxvt_blank_screen_mem(r, page, PSCR(r, page).text,
1448 			PSCR(r, page).rend, row, PVTS(r, page)->rstyle);
1449 }
1450 
1451 /* ------------------------------------------------------------------------- */
1452 /*
1453  * Erase part of whole of the screen
1454  * XTERM_SEQ: Clear screen after cursor : ESC [ 0 J
1455  * XTERM_SEQ: Clear screen before cursor: ESC [ 1 J
1456  * XTERM_SEQ: Clear whole screen		: ESC [ 2 J
1457  */
1458 /* EXTPROTO */
1459 void
rxvt_scr_erase_screen(rxvt_t * r,int page,int mode)1460 rxvt_scr_erase_screen(rxvt_t* r, int page, int mode)
1461 {
1462 	int			num;
1463 	RINT32T		row, row_offset;
1464 	rend_t		ren;
1465 	XGCValues	gcvalue;
1466 
1467 	r->h->want_refresh = 1;
1468 	DBG_MSG(2,(stderr, "rxvt_scr_erase_screen %d (%d) at screen row: %d\n", page, mode, CURROW));
1469 	ZERO_SCROLLBACK(r, page);
1470 	RESET_CHSTAT(r, page);
1471 	row_offset = (RINT32T)SVLINES;
1472 
1473 	switch (mode) {
1474 	case 0:			/* erase to end of screen */
1475 		rxvt_selection_check(r, page, 1);
1476 		rxvt_scr_erase_line(r, page, 0);
1477 		row = CURROW + 1;	/* possible OOB */
1478 		num = r->TermWin.nrow - row;
1479 		break;
1480 	case 1:			/* erase to beginning of screen */
1481 		rxvt_selection_check(r, page, 3);
1482 		rxvt_scr_erase_line(r, page, 1);
1483 		row = 0;
1484 		num = CURROW;
1485 		break;
1486 	case 2:			/* erase whole screen */
1487 		rxvt_selection_check(r, page, 3);
1488 		row = 0;
1489 		num = r->TermWin.nrow;
1490 		break;
1491 	default:
1492 		return;
1493 	}
1494 	r->h->refresh_type |= REFRESH_BOUNDS;
1495 	if (SEL(r).op &&
1496 		SEL(r).vt == page &&
1497 		PVTS(r, page)->current_screen == SEL(r).screen &&
1498 		((SEL(r).beg.row >= row && SEL(r).beg.row <= row + num) ||
1499 		 (SEL(r).end.row >= row && SEL(r).end.row <= row + num)))
1500 		CLEAR_SELECTION(r);
1501 	if (row >= r->TermWin.nrow)	/* Out Of Bounds */
1502 		return;
1503 	MIN_IT(num, (r->TermWin.nrow - row));
1504 	if (PVTS(r, page)->rstyle & (RS_RVid | RS_Uline))
1505 		ren = (rend_t) ~RS_None;
1506 	else if (GET_BASEBG(PVTS(r, page)->rstyle) == Color_bg) {
1507 		ren = DEFAULT_RSTYLE;
1508 		CLEAR_ROWS(row, num);
1509 	} else {
1510 		ren = (PVTS(r, page)->rstyle & (RS_fgMask | RS_bgMask));
1511 		gcvalue.foreground = r->PixColors[GET_BGCOLOR(PVTS(r, page)->rstyle)];
1512 		XChangeGC(r->Xdisplay, r->TermWin.gc, GCForeground, &gcvalue);
1513 		ERASE_ROWS(row, num);
1514 		gcvalue.foreground = r->PixColors[Color_fg];
1515 		XChangeGC(r->Xdisplay, r->TermWin.gc, GCForeground, &gcvalue);
1516 	}
1517 	for (; num--; row++) {
1518 		rxvt_blank_screen_mem(r, page, PSCR(r, page).text,
1519 			PSCR(r, page).rend,
1520 			(unsigned int)(row + row_offset), PVTS(r, page)->rstyle);
1521 		PSCR(r, page).tlen[row + row_offset] = 0;
1522 		rxvt_blank_line(PVTS(r, page)->drawn_text[row], PVTS(r, page)->drawn_rend[row],
1523 			(unsigned int)r->TermWin.ncol, ren);
1524 	}
1525 }
1526 
1527 /* ------------------------------------------------------------------------- */
1528 /*
1529  * Fill the screen with `E's
1530  * XTERM_SEQ: Screen Alignment Test: ESC # 8
1531  */
1532 /* EXTPROTO */
1533 void
rxvt_scr_E(rxvt_t * r,int page)1534 rxvt_scr_E(rxvt_t* r, int page)
1535 {
1536 	int			 i, j, k;
1537 	rend_t		 *r1, fs;
1538 
1539 	r->h->want_refresh = 1;
1540 	r->h->num_scr_allow = 0;
1541 	ZERO_SCROLLBACK(r, page);
1542 	RESET_CHSTAT(r, page);
1543 	rxvt_selection_check(r, page, 3);
1544 
1545 	fs = PVTS(r, page)->rstyle;
1546 	for (k = SVLINES, i = r->TermWin.nrow; i--; k++) {
1547 		PSCR(r, page).tlen[k] = r->TermWin.ncol;	/* make the `E's selectable */
1548 		MEMSET(PSCR(r, page).text[k], 'E', r->TermWin.ncol);
1549 		for (r1 = PSCR(r, page).rend[k], j = r->TermWin.ncol; j--; )
1550 			*r1++ = fs;
1551 	}
1552 }
1553 
1554 /* ------------------------------------------------------------------------- */
1555 /*
1556  * Insert/Delete <count> lines
1557  */
1558 /* EXTPROTO */
1559 void
rxvt_scr_insdel_lines(rxvt_t * r,int page,int count,int insdel)1560 rxvt_scr_insdel_lines(rxvt_t* r, int page, int count, int insdel)
1561 {
1562 	int			 end;
1563 
1564 	ZERO_SCROLLBACK(r, page);
1565 	RESET_CHSTAT(r, page);
1566 	rxvt_selection_check(r, page, 1);
1567 
1568 	if (CURROW > PSCR(r, page).bscroll)
1569 		return;
1570 
1571 	end = PSCR(r, page).bscroll - CURROW + 1;
1572 	if (count > end) {
1573 		if (insdel == DELETE)
1574 			return;
1575 		else if (insdel == INSERT)
1576 			count = end;
1577 	}
1578 	PSCR(r, page).flags &= ~Screen_WrapNext;
1579 
1580 	rxvt_scroll_text(r, page, CURROW,
1581 		PSCR(r, page).bscroll, insdel * count, 0);
1582 }
1583 
1584 /* ------------------------------------------------------------------------- */
1585 /*
1586  * Insert/Delete <count> characters from the current position
1587  */
1588 /* EXTPROTO */
1589 void
rxvt_scr_insdel_chars(rxvt_t * r,int page,int count,int insdel)1590 rxvt_scr_insdel_chars(rxvt_t* r, int page, int count, int insdel)
1591 {
1592 	int			col, row;
1593 	rend_t		tr;
1594 	text_t*		stp;
1595 	rend_t*		srp;
1596 	RINT16T*	slp;
1597 
1598 	r->h->want_refresh = 1;
1599 	ZERO_SCROLLBACK(r, page);
1600 #if 0
1601 	RESET_CHSTAT(r, page);
1602 #endif
1603 	if (count <= 0)
1604 		return;
1605 
1606 	rxvt_selection_check(r, page, 1);
1607 	MIN_IT(count, (r->TermWin.ncol - CURCOL));
1608 
1609 	row = CURROW + SVLINES;
1610 	PSCR(r, page).flags &= ~Screen_WrapNext;
1611 
1612 	stp = PSCR(r, page).text[row];
1613 	srp = PSCR(r, page).rend[row];
1614 	slp = &(PSCR(r, page).tlen[row]);
1615 	switch (insdel) {
1616 	case INSERT:
1617 		for (col = r->TermWin.ncol - 1; (col - count) >= CURCOL; col--) {
1618 			stp[col] = stp[col - count];
1619 			srp[col] = srp[col - count];
1620 		}
1621 		if (*slp != -1) {
1622 			*slp += count;
1623 			MIN_IT(*slp, r->TermWin.ncol);
1624 		}
1625 		if (SEL(r).op &&
1626 			SEL(r).vt == page &&
1627 			PVTS(r, page)->current_screen == SEL(r).screen &&
1628 			RC_ROW_ATAFTER(SEL(r).beg, PSCR(r, page).cur)) {
1629 			if (SEL(r).end.row != CURROW ||
1630 				(SEL(r).end.col + count >= r->TermWin.ncol))
1631 				CLEAR_SELECTION(r);
1632 			else {		/* shift selection */
1633 				SEL(r).beg.col += count;
1634 				SEL(r).mark.col += count;	/* XXX: yes? */
1635 				SEL(r).end.col += count;
1636 			}
1637 		}
1638 		rxvt_blank_line(&(stp[CURCOL]),
1639 			&(srp[CURCOL]),
1640 			(unsigned int)count, PVTS(r, page)->rstyle);
1641 		break;
1642 
1643 	case ERASE:
1644 		CURCOL += count;	/* don't worry if > r->TermWin.ncol */
1645 		rxvt_selection_check(r, page, 1);
1646 		CURCOL -= count;
1647 		rxvt_blank_line(&(stp[CURCOL]),
1648 			&(srp[CURCOL]),
1649 			(unsigned int)count, PVTS(r, page)->rstyle);
1650 		break;
1651 
1652 	case DELETE:
1653 		tr = srp[r->TermWin.ncol - 1]
1654 			 & (RS_fgMask | RS_bgMask | RS_baseattrMask);
1655 		for (col = CURCOL; (col + count) < r->TermWin.ncol; col++) {
1656 			stp[col] = stp[col + count];
1657 			srp[col] = srp[col + count];
1658 		}
1659 		rxvt_blank_line(&(stp[r->TermWin.ncol - count]),
1660 			&(srp[r->TermWin.ncol - count]),
1661 			(unsigned int)count, tr);
1662 		if (*slp == -1)	/* break line continuation */
1663 			*slp = r->TermWin.ncol;
1664 		*slp -= count;
1665 		MAX_IT(*slp, 0);
1666 		if (SEL(r).op &&
1667 			SEL(r).vt == page &&
1668 			PVTS(r, page)->current_screen == SEL(r).screen &&
1669 			RC_ROW_ATAFTER(SEL(r).beg, PSCR(r, page).cur)) {
1670 			if (SEL(r).end.row != CURROW ||
1671 				(CURCOL >= SEL(r).beg.col - count) ||
1672 				SEL(r).end.col >= r->TermWin.ncol)
1673 				CLEAR_SELECTION(r);
1674 			else {
1675 				/* shift selection */
1676 				SEL(r).beg.col -= count;
1677 				SEL(r).mark.col -= count;	/* XXX: yes? */
1678 				SEL(r).end.col -= count;
1679 			}
1680 		}
1681 		break;
1682 	}
1683 #if 0
1684 	if (IS_MULTI2(srp[0])) {
1685 		srp[0] &= ~RS_multiMask;
1686 		stp[0] = ' ';
1687 	}
1688 	if (IS_MULTI1(srp[r->TermWin.ncol - 1])) {
1689 		srp[r->TermWin.ncol - 1] &= ~RS_multiMask;
1690 		stp[r->TermWin.ncol - 1] = ' ';
1691 	}
1692 #endif
1693 }
1694 
1695 /* ------------------------------------------------------------------------- */
1696 /*
1697  * Set the scrolling region
1698  * XTERM_SEQ: Set region <top> - <bot> inclusive: ESC [ <top> ; <bot> r
1699  */
1700 /* EXTPROTO */
1701 void
rxvt_scr_scroll_region(rxvt_t * r,int page,int top,int bot)1702 rxvt_scr_scroll_region(rxvt_t* r, int page, int top, int bot)
1703 {
1704 	MAX_IT(top, 0);
1705 	MIN_IT(bot, (int)r->TermWin.nrow - 1);
1706 	if (top > bot)
1707 		return;
1708 	PSCR(r, page).tscroll = top;
1709 	PSCR(r, page).bscroll = bot;
1710 	rxvt_scr_gotorc(r, page, 0, 0, 0);
1711 }
1712 
1713 /* ------------------------------------------------------------------------- */
1714 /*
1715  * Make the cursor visible/invisible
1716  * XTERM_SEQ: Make cursor visible  : ESC [ ? 25 h
1717  * XTERM_SEQ: Make cursor invisible: ESC [ ? 25 l
1718  */
1719 /* EXTPROTO */
1720 void
rxvt_scr_cursor_visible(rxvt_t * r,int page,int mode)1721 rxvt_scr_cursor_visible(rxvt_t* r, int page, int mode)
1722 {
1723 	r->h->want_refresh = 1;
1724 	if (mode)
1725 		PSCR(r, page).flags |= Screen_VisibleCursor;
1726 	else
1727 		PSCR(r, page).flags &= ~Screen_VisibleCursor;
1728 }
1729 
1730 /* ------------------------------------------------------------------------- */
1731 /*
1732  * Set/unset automatic wrapping
1733  * XTERM_SEQ: Set Wraparound  : ESC [ ? 7 h
1734  * XTERM_SEQ: Unset Wraparound: ESC [ ? 7 l
1735  */
1736 /* EXTPROTO */
1737 void
rxvt_scr_autowrap(rxvt_t * r,int page,int mode)1738 rxvt_scr_autowrap(rxvt_t* r, int page, int mode)
1739 {
1740 	if (mode)
1741 		PSCR(r, page).flags |= Screen_Autowrap;
1742 	else
1743 		PSCR(r, page).flags &= ~(Screen_Autowrap | Screen_WrapNext);
1744 }
1745 
1746 /* ------------------------------------------------------------------------- */
1747 /*
1748  * Set/unset margin origin mode
1749  * Absolute mode: line numbers are counted relative to top margin of screen
1750  *	  and the cursor can be moved outside the scrolling region.
1751  * Relative mode: line numbers are relative to top margin of scrolling region
1752  *	  and the cursor cannot be moved outside.
1753  * XTERM_SEQ: Set Absolute: ESC [ ? 6 h
1754  * XTERM_SEQ: Set Relative: ESC [ ? 6 l
1755  */
1756 /* EXTPROTO */
1757 void
rxvt_scr_relative_origin(rxvt_t * r,int page,int mode)1758 rxvt_scr_relative_origin(rxvt_t* r, int page, int mode)
1759 {
1760 	if (mode)
1761 		PSCR(r, page).flags |= Screen_Relative;
1762 	else
1763 		PSCR(r, page).flags &= ~Screen_Relative;
1764 	rxvt_scr_gotorc(r, page, 0, 0, 0);
1765 }
1766 
1767 /* ------------------------------------------------------------------------- */
1768 /*
1769  * Set insert/replace mode
1770  * XTERM_SEQ: Set Insert mode : ESC [ ? 4 h
1771  * XTERM_SEQ: Set Replace mode: ESC [ ? 4 l
1772  */
1773 /* EXTPROTO */
1774 void
rxvt_scr_insert_mode(rxvt_t * r,int page,int mode)1775 rxvt_scr_insert_mode(rxvt_t* r, int page, int mode)
1776 {
1777 	if (mode)
1778 		PSCR(r, page).flags |= Screen_Insert;
1779 	else
1780 		PSCR(r, page).flags &= ~Screen_Insert;
1781 }
1782 
1783 /* ------------------------------------------------------------------------- */
1784 /*
1785  * Set/Unset tabs
1786  * XTERM_SEQ: Set tab at current column  : ESC H
1787  * XTERM_SEQ: Clear tab at current column: ESC [ 0 g
1788  * XTERM_SEQ: Clear all tabs			 : ESC [ 3 g
1789  */
1790 /* EXTPROTO */
1791 void
rxvt_scr_set_tab(rxvt_t * r,int page,int mode)1792 rxvt_scr_set_tab(rxvt_t* r, int page, int mode)
1793 {
1794 	if (mode < 0)
1795 		MEMSET(r->tabstop, 0, r->TermWin.ncol * sizeof(char));
1796 	else if (PSCR(r, page).cur.col < r->TermWin.ncol)
1797 		r->tabstop[PSCR(r, page).cur.col] = (mode ? 1 : 0);
1798 }
1799 
1800 /* ------------------------------------------------------------------------- */
1801 /*
1802  * Set reverse/normal video
1803  * XTERM_SEQ: Reverse video: ESC [ ? 5 h
1804  * XTERM_SEQ: Normal video : ESC [ ? 5 l
1805  */
1806 /* EXTPROTO */
1807 void
rxvt_scr_rvideo_mode(rxvt_t * r,int page,int mode)1808 rxvt_scr_rvideo_mode(rxvt_t* r, int page, int mode)
1809 {
1810 	if (PVTS(r, page)->rvideo != mode) {
1811 		PVTS(r, page)->rvideo = mode;
1812 		SWAP_IT(r->PixColors[Color_fg], r->PixColors[Color_bg],
1813 			unsigned long);
1814 #if defined(BACKGROUND_IMAGE)
1815 		if (PVTS(r, page)->bg.pixmap == None)
1816 #endif
1817 #if defined(TRANSPARENT)
1818 			if (!(r->Options & Opt_transparent) ||
1819 				r->h->am_transparent == 0)
1820 #endif
1821 				XSetWindowBackground(r->Xdisplay, PVTS(r, page)->vt,
1822 					 r->PixColors[Color_bg]);
1823 
1824 		XSetForeground (r->Xdisplay, r->TermWin.gc, r->PixColors[Color_fg]);
1825 		XSetBackground (r->Xdisplay, r->TermWin.gc, r->PixColors[Color_bg]);
1826 		rxvt_scr_clear(r, page);
1827 		rxvt_scr_touch(r, page, True);
1828 	}
1829 }
1830 
1831 /* ------------------------------------------------------------------------- */
1832 /*
1833  * Report current cursor position
1834  * XTERM_SEQ: Report position: ESC [ 6 n
1835  */
1836 /* EXTPROTO */
1837 void
rxvt_scr_report_position(rxvt_t * r,int page)1838 rxvt_scr_report_position(rxvt_t* r, int page)
1839 {
1840 	rxvt_tt_printf(r, page, "\033[%d;%dR", CURROW + 1, CURCOL + 1);
1841 }
1842 
1843 /* ------------------------------------------------------------------------- *
1844  *								  FONTS									*
1845  * ------------------------------------------------------------------------- */
1846 
1847 /*
1848  * Set font style
1849  */
1850 /* INTPROTO */
1851 void
rxvt_set_font_style(rxvt_t * r,int page)1852 rxvt_set_font_style(rxvt_t *r, int page)
1853 {
1854 	PVTS(r, page)->rstyle &= ~RS_fontMask;
1855 	switch (PVTS(r, page)->charsets[PSCR(r, page).charset]) {
1856 	case '0':			/* DEC Special Character & Line Drawing Set */
1857 		PVTS(r, page)->rstyle |= RS_acsFont;
1858 		break;
1859 	case 'A':			/* United Kingdom (UK) */
1860 		PVTS(r, page)->rstyle |= RS_ukFont;
1861 		break;
1862 	case 'B':			/* United States (USASCII) */
1863 		break;
1864 	case '<':			/* Multinational character set */
1865 		break;
1866 	case '5':			/* Finnish character set */
1867 		break;
1868 	case 'C':			/* Finnish character set */
1869 		break;
1870 	case 'K':			/* German character set */
1871 		break;
1872 	}
1873 }
1874 
1875 /* ------------------------------------------------------------------------- */
1876 /*
1877  * Choose a font
1878  * XTERM_SEQ: Invoke G0 character set: CTRL-O
1879  * XTERM_SEQ: Invoke G1 character set: CTRL-N
1880  * XTERM_SEQ: Invoke G2 character set: ESC N
1881  * XTERM_SEQ: Invoke G3 character set: ESC O
1882  */
1883 /* EXTPROTO */
1884 void
rxvt_scr_charset_choose(rxvt_t * r,int page,int set)1885 rxvt_scr_charset_choose(rxvt_t* r, int page, int set)
1886 {
1887 	PSCR(r, page).charset = set;
1888 	rxvt_set_font_style(r, page);
1889 }
1890 
1891 /* ------------------------------------------------------------------------- */
1892 /*
1893  * Set a font
1894  * XTERM_SEQ: Set G0 character set: ESC ( <C>
1895  * XTERM_SEQ: Set G1 character set: ESC ) <C>
1896  * XTERM_SEQ: Set G2 character set: ESC * <C>
1897  * XTERM_SEQ: Set G3 character set: ESC + <C>
1898  * See set_font_style for possible values for <C>
1899  */
1900 /* EXTPROTO */
1901 void
rxvt_scr_charset_set(rxvt_t * r,int page,int set,unsigned int ch)1902 rxvt_scr_charset_set(rxvt_t* r, int page, int set, unsigned int ch)
1903 {
1904 #ifdef MULTICHAR_SET
1905 	PVTS(r, page)->multi_byte = !!(set < 0);
1906 	set = abs(set);
1907 #endif
1908 	PVTS(r, page)->charsets[set] = (unsigned char)ch;
1909 	rxvt_set_font_style(r, page);
1910 }
1911 
1912 /* ------------------------------------------------------------------------- *
1913  *						MAJOR SCREEN MANIPULATION						  *
1914  * ------------------------------------------------------------------------- */
1915 
1916 /*
1917  * Refresh an area
1918  */
1919 enum {
1920 	PART_BEG = 0,
1921 	PART_END,
1922 	RC_COUNT
1923 };
1924 
1925 /* EXTPROTO */
1926 void
rxvt_scr_expose(rxvt_t * r,int page,int x,int y,int width,int height,Bool refresh)1927 rxvt_scr_expose(rxvt_t* r, int page, int x, int y, int width, int height, Bool refresh)
1928 {
1929 	int			 i;
1930 	row_col_t	   rc[RC_COUNT];
1931 
1932 	if (PVTS(r, page)->drawn_text == NULL)	/* sanity check */
1933 		return;
1934 
1935 	x = max(x, (int)r->TermWin.int_bwidth);
1936 	x = min(x, (int)r->szHint.width);
1937 	y = max(y, (int)r->TermWin.int_bwidth);
1938 	y = min(y, (int)r->szHint.height);
1939 
1940 	/* round down */
1941 	rc[PART_BEG].col = Pixel2Col(x);
1942 	rc[PART_BEG].row = Pixel2Row(y);
1943 	/* round up */
1944 	rc[PART_END].col = Pixel2Width(x + width + r->TermWin.fwidth - 1);
1945 	rc[PART_END].row = Pixel2Row(y + height + r->TermWin.fheight - 1);
1946 
1947 	/* sanity checks */
1948 	for (i = PART_BEG; i < RC_COUNT; i++) {
1949 		MIN_IT(rc[i].col, r->TermWin.ncol - 1);
1950 		MIN_IT(rc[i].row, r->TermWin.nrow - 1);
1951 	}
1952 
1953 	DBG_MSG(2,(stderr, "rxvt_scr_expose %d (x:%d, y:%d, w:%d, h:%d) area (c:%d,r:%d)-(c:%d,r:%d)\n", page, x, y, width, height, rc[PART_BEG].col, rc[PART_BEG].row, rc[PART_END].col, rc[PART_END].row));
1954 
1955 	for (i = rc[PART_BEG].row; i <= rc[PART_END].row; i++)	{
1956 		register int	j = rc[PART_BEG].col;
1957 		register int	k = rc[PART_END].col - rc[PART_BEG].col + 1;
1958 		DBG_MSG(2,(stderr, " memset drawn_text[%d][%d], len=%d\n", i, j, k));
1959 		MEMSET(&(PVTS(r, page)->drawn_text[i][j]), 0, k);
1960 	}
1961 
1962 	if (refresh)
1963 		rxvt_scr_refresh(r, page, SLOW_REFRESH | REFRESH_BOUNDS);
1964 }
1965 
1966 /* ------------------------------------------------------------------------- */
1967 /*
1968  * Refresh the entire screen
1969  */
1970 /* EXTPROTO */
1971 void
rxvt_scr_touch(rxvt_t * r,int page,Bool refresh)1972 rxvt_scr_touch(rxvt_t* r, int page, Bool refresh)
1973 {
1974 	rxvt_scr_expose(r, page, 0, 0, VT_WIDTH(r), VT_HEIGHT(r), refresh);
1975 }
1976 
1977 /* ------------------------------------------------------------------------- */
1978 /*
1979  * Move the display so that the line represented by scrollbar value Y is at
1980  * the top of the screen
1981  */
1982 /* EXTPROTO */
1983 int
rxvt_scr_move_to(rxvt_t * r,int page,int y,int len)1984 rxvt_scr_move_to(rxvt_t* r, int page, int y, int len)
1985 {
1986 	long			p = 0;
1987 	RUINT16T		oldviewstart;
1988 
1989 	oldviewstart = VSTART;
1990 	if (y < len) {
1991 		p = (r->TermWin.nrow + PVTS(r, page)->nscrolled) * (len - y) / len;
1992 		p -= (long)(r->TermWin.nrow - 1);
1993 		p = max(p, 0);
1994 	}
1995 	VSTART = (RUINT16T)min(p, PVTS(r, page)->nscrolled);
1996 	DBG_MSG(2,(stderr, "rxvt_scr_move_to %d (%d, %d) view_start:%d\n", page, y, len, VSTART));
1997 
1998 	return rxvt_scr_change_view(r, page, oldviewstart);
1999 }
2000 
2001 /* ------------------------------------------------------------------------- */
2002 /*
2003  * Page the screen up/down nlines
2004  * direction should be UP or DN
2005  */
2006 /* EXTPROTO */
2007 int
rxvt_scr_page(rxvt_t * r,int page,enum page_dirn direction,int nlines)2008 rxvt_scr_page(rxvt_t* r, int page, enum page_dirn direction, int nlines)
2009 {
2010 	int			n;
2011 	RUINT16T	oldviewstart;
2012 
2013 	DBG_MSG(2,(stderr, "rxvt_scr_page %d (%s, %d) view_start:%d\n", page, ((direction == UP) ? "UP" : "DN"), nlines, VSTART));
2014 
2015 	assert((nlines >= 0) && (nlines <= r->TermWin.nrow));
2016 	oldviewstart = VSTART;
2017 	if (direction == UP) {
2018 		n = VSTART + nlines;
2019 		VSTART = min(n, PVTS(r, page)->nscrolled);
2020 	}
2021 	else {
2022 		n = VSTART - nlines;
2023 		VSTART = max(n, 0);
2024 	}
2025 	return rxvt_scr_change_view(r, page, oldviewstart);
2026 }
2027 
2028 
2029 /* INTPROTO */
2030 int
rxvt_scr_change_view(rxvt_t * r,int page,RUINT16T oldviewstart)2031 rxvt_scr_change_view(rxvt_t* r, int page, RUINT16T oldviewstart)
2032 {
2033 	if (VSTART != oldviewstart) {
2034 		r->h->want_refresh = 1;
2035 		PVTS(r, page)->num_scr -= (VSTART - oldviewstart);
2036 	}
2037 	return (int)(VSTART - oldviewstart);
2038 }
2039 
2040 
2041 /* ------------------------------------------------------------------------- */
2042 /* EXTPROTO */
2043 void
rxvt_scr_bell(rxvt_t * r)2044 rxvt_scr_bell(rxvt_t *r)
2045 {
2046 #ifndef NO_BELL
2047 
2048 #if defined(THROTTLE_BELL_MSEC) && THROTTLE_BELL_MSEC > 0
2049 	/* Maximal number of bell per pre-defined time interval */
2050 	static int				bellcount = 0;
2051 	static struct timeval	tvbase = {0, 0};
2052 	struct timeval			tvnow = {0, 0};
2053 	long					tminterval;
2054 
2055 	if (gettimeofday (&tvnow, NULL) >= 0)	{
2056 		if (0 == tvbase.tv_sec && 0 == tvbase.tv_usec)	{
2057 			/* first time bell, try avoid integer overflow */
2058 			tvbase = tvnow;
2059 			tminterval = 0;
2060 		}
2061 		else
2062 			tminterval = (tvnow.tv_sec - tvbase.tv_sec) * 1000 +
2063 						(tvnow.tv_usec - tvbase.tv_usec) / 1000;
2064 		if (tminterval > THROTTLE_BELL_MSEC)	{
2065 			tvbase = tvnow;
2066 			bellcount = 1;
2067 		}
2068 		else if (bellcount ++ >= THROTTLE_BELL_COUNT)	{
2069 			return;
2070 		}
2071 	}
2072 #endif	/* THROTTLE_BELL_MSEC && THROTTLE_BELL_MSEC > 0 */
2073 
2074 	if (r->h->rs[Rs_bellCommand])	{
2075 		/* execute bell command */
2076 		system (r->h->rs[Rs_bellCommand]);
2077 		return ;
2078 	}
2079 
2080 # ifndef NO_MAPALERT
2081 #  ifdef MAPALERT_OPTION
2082 	if (r->Options & Opt_mapAlert)
2083 #  endif
2084 		XMapWindow(r->Xdisplay, r->TermWin.parent);
2085 # endif
2086 	if (r->Options & Opt_visualBell) {
2087 		/* refresh also done */
2088 		rxvt_scr_rvideo_mode(r, ATAB(r), !AVTS(r)->rvideo);
2089 		rxvt_scr_rvideo_mode(r, ATAB(r), !AVTS(r)->rvideo);
2090 	}
2091 	else
2092 		XBell(r->Xdisplay, 0);
2093 #endif
2094 }
2095 
2096 /* ------------------------------------------------------------------------- */
2097 /* ARGSUSED */
2098 /* EXTPROTO */
2099 void
rxvt_scr_printscreen(rxvt_t * r,int page,int fullhist)2100 rxvt_scr_printscreen(rxvt_t* r, int page, int fullhist)
2101 {
2102 #ifdef PRINTPIPE
2103 	int			i, r1, nrows, row_offset;
2104 	text_t*		t;
2105 	FILE*		fd;
2106 
2107 	if ((fd = rxvt_popen_printer(r)) == NULL)
2108 		return;
2109 	nrows = r->TermWin.nrow;
2110 	row_offset = SVLINES;
2111 	if (!fullhist)
2112 		row_offset -= VSTART;
2113 	else {
2114 		nrows += PVTS(r, page)->nscrolled;
2115 		row_offset -= PVTS(r, page)->nscrolled;
2116 	}
2117 
2118 	for (r1 = 0; r1 < nrows; r1++) {
2119 		t = PSCR(r, page).text[r1 + row_offset];
2120 		for (i = r->TermWin.ncol - 1; i >= 0; i--)
2121 			if (!isspace(t[i]))
2122 			break;
2123 		fprintf(fd, "%.*s\n", (i + 1), t);
2124 	}
2125 	rxvt_pclose_printer(fd);
2126 #endif
2127 }
2128 
2129 
2130 #ifdef TEXT_SHADOW
2131 /* INTPROTO */
2132 void
rxvt_set_clipping(rxvt_t * r,GC gc,int x,int y,int len,int mfont,int * offx,int * offy)2133 rxvt_set_clipping (rxvt_t* r, GC gc, int x, int y, int len, int mfont, int* offx, int* offy)
2134 {
2135 	/* mfont is a flag whether the output string is multi-byte.
2136 	** if so, we need to extend its length twice assuming string
2137 	** is 2-byte string */
2138 	register unsigned int	hx = Width2Pixel(1) * len * (mfont+1);
2139 	register unsigned int	hy = Height2Pixel(1) * 1;
2140 	XRectangle		rectangle;
2141 
2142 
2143 	assert (offx);	*offx = 0;
2144 	assert (offy);	*offy = 0;
2145 
2146 	if (SHADOW_NONE == r->TermWin.shadow_mode)
2147 		return;	/* shortcut */
2148 
2149 	DBG_MSG(3, (stderr, "rxvt_set_clipping (len=%d, mfont=%d)\n", len, mfont));
2150 
2151 	switch (r->TermWin.shadow_mode)	{
2152 	case SHADOW_TOP:
2153 		rectangle.x = 0; rectangle.y = -1;
2154 		*offx = 0; *offy = -1;
2155 		break;
2156 	case SHADOW_BOTTOM:
2157 		rectangle.x = 0; rectangle.y = 1;
2158 		*offx = 0; *offy = 1;
2159 		break;
2160 	case SHADOW_LEFT:
2161 		rectangle.x = -1; rectangle.y = 0;
2162 		*offx = -1; *offy = 0;
2163 		break;
2164 	case SHADOW_RIGHT:
2165 		rectangle.x = 1; rectangle.y = 0;
2166 		*offx = 1; *offy = 0;
2167 		break;
2168 	case SHADOW_TOPLEFT:
2169 		rectangle.x = -1; rectangle.y = -1;
2170 		*offx = -1; *offy = -1;
2171 		break;
2172 	case SHADOW_TOPRIGHT:
2173 		rectangle.x = 1; rectangle.y = -1;
2174 		*offx = 1; *offy = -1;
2175 		break;
2176 	case SHADOW_BOTLEFT:
2177 		rectangle.x = -1; rectangle.y = 1;
2178 		*offx = -1; *offy = 1;
2179 		break;
2180 	case SHADOW_BOTRIGHT:
2181 		rectangle.x = 1; rectangle.y = 1;
2182 		*offx = 1; *offy = 1;
2183 		break;
2184 	default:
2185 		assert (0);
2186 		break;
2187 	}
2188 	/*
2189 	rectangle.x = 0;
2190 	rectangle.y = 0;
2191 	*/
2192 	rectangle.width  = hx;
2193 	rectangle.height = hy;
2194 
2195 	XSetClipRectangles (r->Xdisplay, gc, x, y-hy, &rectangle, 1, Unsorted);
2196 }
2197 
2198 
2199 /* INTPROTO */
2200 void
rxvt_free_clipping(rxvt_t * r,GC gc)2201 rxvt_free_clipping (rxvt_t* r, GC gc)
2202 {
2203 	XRectangle		rectangle;
2204 
2205 	if (SHADOW_NONE == r->TermWin.shadow_mode)
2206 		return;	/* shortcut */
2207 
2208 	rectangle.x = 0;
2209 	rectangle.y = 0;
2210 	if (gc == r->TermWin.gc)	{
2211 		rectangle.width  = VT_WIDTH(r);
2212 		rectangle.height = VT_HEIGHT(r);
2213 	}
2214 	else
2215 	if (gc == r->tabBar.gc)		{
2216 		rectangle.width  = TWIN_WIDTH(r);
2217 		rectangle.height = rxvt_tabbar_rheight(r);
2218 	}
2219 	XSetClipRectangles (r->Xdisplay, gc, 0, 0, &rectangle, 1, Unsorted);
2220 }
2221 #endif	/* TEXT_SHADOW */
2222 
2223 
2224 void inline
rxvt_clear_area(rxvt_t * r,int page,int x,int y,unsigned int w,unsigned int h)2225 rxvt_clear_area (rxvt_t* r, int page, int x, int y, unsigned int w, unsigned int h)
2226 {
2227 	/*
2228 #ifdef XFT_SUPPORT
2229 	if ((r->Options & Opt_xft) && PVTS(r, page)->xftvt)	{
2230 		XftDrawRect (PVTS(r, page)->xftvt, &(r->XftColors[Color_bg]),
2231 			x, y, w, h);
2232 	}
2233 	else
2234 #endif
2235 	*/
2236 	DBG_MSG(9, (stderr, "clear area (%d, %d, %d, %d)\n", x,y,w,h));
2237 	XClearArea (r->Xdisplay, drawBuffer, x, y, w, h, False);
2238 }
2239 
2240 
2241 void inline
rxvt_fill_rectangle(rxvt_t * r,int page,int x,int y,unsigned int w,unsigned int h)2242 rxvt_fill_rectangle (rxvt_t* r, int page, int x, int y, unsigned int w, unsigned int h)
2243 {
2244 	/*
2245 #ifdef XFT_SUPPORT
2246 	if ((r->Options & Opt_xft) && PVTS(r, page)->xftvt)	{
2247 		XftDrawRect (PVTS(r, page)->xftvt, &(r->XftColors[Color_bg]),
2248 			x, y, w, h);
2249 	}
2250 	else
2251 #endif
2252 	*/
2253 	DBG_MSG(9, (stderr, "fill rectangle (%d, %d, %d, %d)\n", x,y,w,h));
2254 	XFillRectangle (r->Xdisplay, drawBuffer, r->TermWin.gc, x, y, w, h);
2255 }
2256 
2257 
2258 /* ------------------------------------------------------------------------- */
2259 /*
2260  * Refresh the screen
2261  * PVTS(r, page)->drawn_text/PVTS(r, page)->drawn_rend contain the screen information before the update.
2262  * PSCR(r, page).text/PSCR(r, page).rend contain what the screen will change to.
2263  */
2264 
2265 
2266 #define X11_DRAW_STRING_8			(1)
2267 #define X11_DRAW_STRING_16			(2)
2268 #define X11_DRAW_IMAGE_STRING_8		(3)
2269 #define X11_DRAW_IMAGE_STRING_16	(4)
2270 #define XFT_DRAW_STRING_8			(5)
2271 #define XFT_DRAW_STRING_16			(6)
2272 #define XFT_DRAW_STRING_32			(7)
2273 #define XFT_DRAW_STRING_UTF8		(8)
2274 #define XFT_DRAW_IMAGE_STRING_8		(9)
2275 #define XFT_DRAW_IMAGE_STRING_16	(10)
2276 #define XFT_DRAW_IMAGE_STRING_32	(11)
2277 #define XFT_DRAW_IMAGE_STRING_UTF8	(12)
2278 
2279 
2280 #ifdef XFT_SUPPORT
2281 /*
2282 ** len: number of characters to draw. for UTF-8 string, it is the
2283 **      number of characters * 2 of the original 16-bits string
2284 */
2285 /* EXTPROTO */
2286 void
rxvt_draw_string_xft(rxvt_t * r,XftDraw * win,GC gc,XftColor * fore,int x,int y,char * str,int len,void (* xftdraw_string)())2287 rxvt_draw_string_xft (rxvt_t* r, XftDraw* win, GC gc, XftColor* fore, int x, int y, char* str, int len, void (*xftdraw_string)())
2288 {
2289 # ifdef TEXT_SHADOW
2290 	if (r->h->rs[Rs_textShadow] &&
2291 		SHADOW_NONE != r->TermWin.shadow_mode)	{
2292 		int		sx, sy;
2293 
2294 		DBG_MSG(3, (stderr, "handling text shadow for %s (%d)\n", str, len));
2295 
2296 		rxvt_set_clipping (r, gc, x, y, len,
2297 			(XftDrawString8 != xftdraw_string &&
2298 			 XftDrawStringUtf8 != xftdraw_string), &sx, &sy);
2299 #  ifdef MULTICHAR_SET
2300 		if (XftDrawStringUtf8 == xftdraw_string)	{
2301 			xftdraw_string (win, &(r->TermWin.xftshadow),
2302 				r->TermWin.xftmfont, x+sx, y+sy, str, STRLEN(str));
2303 		}
2304 		else
2305 #  endif	/* MULTICHAR_SET */
2306 		{
2307 			xftdraw_string (win, &(r->TermWin.xftshadow),
2308 				r->TermWin.xftfont, x+sx, y+sy, str, len);
2309 		}
2310 		/*
2311 		** We need to free clipping area, otherwise text on
2312 		** screen may be clipped unexpectedly. Is there a better
2313 		** way to unset it, say, XUnsetClipRectangles?
2314 		*/
2315 		rxvt_free_clipping (r, gc);
2316 	}
2317 # endif	/* TEXT_SHADOW */
2318 
2319 # ifdef MULTICHAR_SET
2320 	if (XftDrawStringUtf8 == xftdraw_string)	{
2321 		xftdraw_string (win, fore, r->TermWin.xftmfont, x, y,
2322 			str, STRLEN(str));
2323 	}
2324 	else
2325 # endif	/* MULTICHAR_SET */
2326 	{
2327 		xftdraw_string (win, fore, r->TermWin.xftfont, x, y, str, len);
2328 	}
2329 }
2330 #endif
2331 
2332 
2333 /*
2334 **	len : number of characters in the string
2335 */
2336 /* EXTPROTO */
2337 void
rxvt_draw_string_x11(rxvt_t * r,Window win,GC gc,int x,int y,char * str,int len,int (* draw_string)())2338 rxvt_draw_string_x11 (rxvt_t* r, Window win, GC gc, int x, int y, char* str, int len, int (*draw_string)())
2339 {
2340 # ifdef TEXT_SHADOW
2341 	if (r->h->rs[Rs_textShadow] &&
2342 		SHADOW_NONE != r->TermWin.shadow_mode)	{
2343 		int		sx, sy;
2344 		XGCValues	gcvalue;
2345 
2346 		DBG_MSG(3, (stderr, "handling text shadow for %s (%d)\n", str, len));
2347 
2348 		XGetGCValues (r->Xdisplay, gc, GCForeground, &gcvalue);
2349 		XSetForeground (r->Xdisplay, gc, r->TermWin.shadow);
2350 		rxvt_set_clipping (r, gc, x, y, len,
2351 			(XDrawString != draw_string &&
2352 			 XDrawImageString != draw_string), &sx, &sy);
2353 		draw_string (r->Xdisplay, win, gc, x+sx, y+sy, str, len);
2354 		XSetForeground (r->Xdisplay, gc, gcvalue.foreground);
2355 		/*
2356 		** We need to free clipping area, otherwise text on
2357 		** screen may be clipped unexpectedly. Is there a better
2358 		** way to unset it, say, XUnsetClipRectangles?
2359 		*/
2360 		rxvt_free_clipping (r, gc);
2361 	}
2362 # endif	/* TEXT_SHADOW */
2363 
2364 	DBG_MSG(3, (stderr, "output entire string: %s\n", str));
2365 	draw_string (r->Xdisplay, win, gc, x, y, str, len);
2366 }
2367 
2368 
2369 /*
2370 ** Draw the string:
2371 **    x, y:  top left corner of the string
2372 **    str :  actual string to draw
2373 **    len :  actual number of characters in the string. It is NOT
2374 **           the byte length!
2375 **    drawfunc: function to draw string
2376 **    fore, back: color index to r->PixColors array. It is only
2377 **           used by the XFT drawing, not X11 drawing
2378 */
2379 /* INTPROTO */
2380 void
rxvt_scr_draw_string(rxvt_t * r,int page,int x,int y,char * str,int len,int drawfunc,RUINT16T fore,RUINT16T back)2381 rxvt_scr_draw_string (rxvt_t* r, int page, int x, int y, char* str, int len, int drawfunc, RUINT16T fore, RUINT16T back)
2382 {
2383 #ifdef XFT_SUPPORT
2384 	int		fillback = 0;
2385 	int		adjust;
2386 	void	(*xftdraw_string) () = NULL;
2387 
2388 	switch (drawfunc)	{
2389 		case	XFT_DRAW_IMAGE_STRING_8:
2390 			fillback = 1;
2391 		case	XFT_DRAW_STRING_8:
2392 			xftdraw_string = XftDrawString8; break;
2393 
2394 		case	XFT_DRAW_IMAGE_STRING_16:
2395 			fillback = 1;
2396 		case	XFT_DRAW_STRING_16:
2397 			xftdraw_string = XftDrawString16; break;
2398 	}
2399 
2400 	/*
2401 	** adjust is a variable that records whether each character of
2402 	** the string is 8 bits or 16 bits
2403 	*/
2404 	adjust = (XftDrawString8 == xftdraw_string) ? 0 : 1;
2405 
2406 	if ((r->Options & Opt_xft) && PVTS(r, page)->xftvt &&
2407 		xftdraw_string)	{
2408 		register int	loop;		/* loop iteration number */
2409 		register int	loopitem;	/* each iteration increasing # */
2410 		register int	i;
2411 		/*
2412 		** xft_draw_string_xft should call these two parameters
2413 		*/
2414 		register char*	pstr;		/* string to print */
2415 		register int	plen;		/* string length */
2416 		char*			newstr;
2417 #ifdef MULTICHAR_SET
2418 #  ifdef HAVE_ICONV_H
2419 		char			pbuf[1024];	/* buffer to save UTF-8 string */
2420 #  endif
2421 #endif
2422 
2423 
2424 		/*
2425 		** Xft does not support XDrawImageString, so we need to
2426 		** clear the background of text by ourselves
2427 		*/
2428 		if (fillback)	{
2429 			XGCValues	gcvalue;
2430 
2431 			/* save current foreground color */
2432 			XGetGCValues (r->Xdisplay, r->TermWin.gc, GCForeground,
2433 				&gcvalue);
2434 			/* fill background rectangle using background color */
2435 			XSetForeground (r->Xdisplay, r->TermWin.gc,
2436 				r->PixColors[back]);
2437 			rxvt_fill_rectangle (r, page, x, y,
2438 				Width2Pixel(len * (1 + adjust)), Height2Pixel(1));
2439 			/* restore current foreground color */
2440 			XSetForeground (r->Xdisplay, r->TermWin.gc,
2441 				gcvalue.background);
2442 		}
2443 		/* We use TermWin.xftfont->ascent here */
2444 		y += r->TermWin.xftfont->ascent;
2445 
2446 
2447 		/*
2448 		** Xft does not support XftDrawString16, so we need to
2449 		** convert the string to UTF-8. Here we reencode the
2450 		** string before conversion
2451 		*/
2452 # ifdef MULTICHAR_SET
2453 #  ifdef HAVE_ICONV_H
2454 		if (adjust && (iconv_t) -1 != r->TermWin.xfticonv)	{
2455 			register int	j, newlen = (len << 1);
2456 			switch (r->encoding_method)	{
2457 			case ENC_EUCJ:
2458 			case ENC_GB:
2459 				for (j = 0; j < newlen; j ++)
2460 					str[j] |= 0x80;
2461 				break;
2462 			case ENC_GBK:	/* need to do nothing */
2463 			case ENC_BIG5:	/* need to do nothing */
2464 			default:
2465 				break;
2466 			}
2467 			/* we will use utf8 routine to draw string */
2468 			xftdraw_string = XftDrawStringUtf8;
2469 		}
2470 #  endif
2471 # endif	/* MULTICHAR_SET */
2472 
2473 
2474 		/*
2475 		** If the font is monospace, we print the entire string once,
2476 		** otherwise, print the characters one by one
2477 		*/
2478 		if (r->TermWin.xftmono)	{
2479 			/* print string once for mono font */
2480 			loop = 1;
2481 			loopitem = len;
2482 			/*
2483 			** If XftDrawString8 == xftdraw_string
2484 			**     string length == character number
2485 			** If XftDrawString16 == xftdraw_string
2486 			**     string length == 2 * character number, but we do
2487 			** not need to multiply loopitem by 2 because  the
2488 			** XftDrawString16 takes character numbers.
2489 			**
2490 			** If XftDrawStringUtf8 == xftdraw_string
2491 			**     string length == 2 * character number, but we need
2492 			** to multiply loopitem by 2 because iconv need string
2493 			** length as parameter, not character number.
2494 			*/
2495 			if (XftDrawStringUtf8 == xftdraw_string)
2496 				loopitem <<= 1;
2497 			DBG_MSG(3, (stderr, "output entire mono string\n"));
2498 		}
2499 		/*
2500 		** Non monospace font, but still we can improve the performance
2501 		** by print it once under certain conditions
2502 		*/
2503 # ifdef MULTICHAR_SET
2504 		else
2505 		if (!(r->Options2 & Opt2_xftSlowOutput) &&
2506 			(XftDrawStringUtf8 == xftdraw_string) &&
2507 			(r->TermWin.xftmfont->max_advance_width ==
2508 			 (r->TermWin.fwidth << 1)))	{
2509 			/* print string once for multichar string */
2510 			loop = 1;
2511 			/*
2512 			** If XftDrawStringUtf8 == xftdraw_string
2513 			**     string length == 2 * character number, but we need
2514 			** to multiply loopitem by 2 because iconv need string
2515 			** length as parameter, not character number.
2516 			*/
2517 			loopitem = (len << 1);
2518 			DBG_MSG(3, (stderr, "output entire UTF-8 string\n"));
2519 		}
2520 		else
2521 		if (!(r->Options2 & Opt2_xftSlowOutput) &&
2522 			(XftDrawString16 == xftdraw_string) &&
2523 			(r->TermWin.xftmfont->max_advance_width ==
2524 			 (r->TermWin.fwidth << 1)))	{
2525 			/* print string once for 16-bits string */
2526 			loop = 1;
2527 			loopitem = len;
2528 			DBG_MSG(3, (stderr, "output entire 16-bits string\n"));
2529 		}
2530 # endif	/* MULTICHAR_SET */
2531 		else
2532 		if (r->TermWin.xftfnmono &&
2533 			(XftDrawString8 == xftdraw_string) &&
2534 			(r->TermWin.xftfont->max_advance_width ==
2535 			 r->TermWin.fwidth))	{
2536 			/* print string once for 8-bits string */
2537 			loop = 1;
2538 			loopitem = len;
2539 			DBG_MSG(3, (stderr, "output entire 8-bits string\n"));
2540 		}
2541 		else	{
2542 			/* print string one by one character */
2543 			loop = len;
2544 			loopitem = 1 + adjust;
2545 			DBG_MSG(3, (stderr, "output characters one by one\n"));
2546 		}
2547 
2548 
2549 		newstr = str;	/* string beginning in each iteration */
2550 		for (i = 0; i < loop; i ++)	{
2551 # ifdef MULTICHAR_SET
2552 #  ifdef HAVE_ICONV_H
2553 			if (XftDrawStringUtf8 == xftdraw_string)	{
2554 				/* We should convert the string to UTF-8 */
2555 				char*	buf = pbuf;				/* always init it */
2556 				int		buflen = sizeof(pbuf)-1;/* always init it */
2557 				int		newlen = loopitem;		/* always init it */
2558 				char*	oldstr = newstr;
2559 				iconv (r->TermWin.xfticonv, (char**)(&newstr),
2560 					(size_t*) &newlen, &buf, (size_t*) &buflen);
2561 				*buf = (char) 0;	/* set end of string */
2562 				pstr = pbuf;
2563 				/*
2564 				** we should use the length of original string, not
2565 				** UTF-8 string here!!!
2566 				*/
2567 				plen = loopitem;
2568 				/*
2569 				** reset newstr to old position, we will increase it
2570 				** later
2571 				*/
2572 				newstr = oldstr;
2573 			}
2574 			else
2575 #  endif
2576 # endif	/* MULTICHAR_SET */
2577 			{
2578 				/* We do not need to convert the string to UTF-8 */
2579 				pstr = newstr;
2580 				plen = loopitem;
2581 			}
2582 
2583 			rxvt_draw_string_xft(r, PVTS(r, page)->xftvt,
2584 				r->TermWin.gc, &(r->XftColors[fore]),
2585 				x, y, pstr, plen, xftdraw_string);
2586 
2587 			x += Width2Pixel (loopitem);
2588 			newstr += loopitem;	/* next string to display */
2589 		}
2590 	}
2591 	else
2592 #endif	/* XFT_SUPPORT */
2593 	{
2594 		int		(*draw_string) ();
2595 		switch (drawfunc)	{
2596 			case	X11_DRAW_STRING_8:
2597 				draw_string = XDrawString; break;
2598 			case	X11_DRAW_STRING_16:
2599 				draw_string = XDrawString16; break;
2600 			case	X11_DRAW_IMAGE_STRING_8:
2601 				draw_string = XDrawImageString; break;
2602 			case	X11_DRAW_IMAGE_STRING_16:
2603 				draw_string = XDrawImageString16; break;
2604 
2605 			case	XFT_DRAW_STRING_8:		/* fall back to X11 */
2606 				draw_string = XDrawString; break;
2607 			case	XFT_DRAW_STRING_16:		/* fall back to X11 */
2608 			case	XFT_DRAW_STRING_32:		/* fall back to X11 */
2609 			case	XFT_DRAW_STRING_UTF8:	/* fall back to X11 */
2610 				draw_string = XDrawString16; break;
2611 
2612 			case	XFT_DRAW_IMAGE_STRING_8:	/* fall back to X11 */
2613 				draw_string = XDrawImageString; break;
2614 			case	XFT_DRAW_IMAGE_STRING_16:	/* fall back to X11 */
2615 			case	XFT_DRAW_IMAGE_STRING_32:	/* fall back to X11 */
2616 			case	XFT_DRAW_IMAGE_STRING_UTF8:	/* fall back to X11 */
2617 				draw_string = XDrawImageString16; break;
2618 
2619 			default:
2620 				draw_string = NULL; break;
2621 		}
2622 
2623 		/* We use TermWin.font->ascent here */
2624 		y += r->TermWin.font->ascent;
2625 
2626 		/* Now draw the string */
2627 		if (draw_string)
2628 			rxvt_draw_string_x11 (r, PVTS(r, page)->vt, r->TermWin.gc,
2629 				x, y, str, len, draw_string);
2630 	}
2631 }
2632 
2633 
2634 
2635 #ifdef XFT_SUPPORT
2636 # ifndef NO_BOLDFONT
2637 /* INTPROTO */
2638 int
rxvt_switch_bold_font(rxvt_t * r)2639 rxvt_switch_bold_font (rxvt_t* r)
2640 {
2641 	/* bold font is not loaded */
2642 	if (NULL == r->TermWin.xftbfont)
2643 		return 0;
2644 	/* bold font is already switched */
2645 	if (r->TermWin.bf_switched)
2646 		return 0;
2647 	/* now switch the bold font */
2648 	SWAP_IT (r->TermWin.xftfont, r->TermWin.xftbfont, XftFont*);
2649 	r->TermWin.bf_switched = 1;
2650 	return 1;
2651 }
2652 
2653 /* INTPROTO */
2654 int
rxvt_restore_bold_font(rxvt_t * r)2655 rxvt_restore_bold_font (rxvt_t* r)
2656 {
2657 	/* bold font is not loaded */
2658 	if (NULL == r->TermWin.xftbfont)
2659 		return 0;
2660 	/* bold font is not switched */
2661 	if (!r->TermWin.bf_switched)
2662 		return 0;
2663 	/* now restore the bold font */
2664 	SWAP_IT (r->TermWin.xftfont, r->TermWin.xftbfont, XftFont*);
2665 	r->TermWin.bf_switched = 0;
2666 	return 1;
2667 }
2668 # endif	/* NO_BOLDFONT */
2669 #endif	/* XFT_SUPPORT */
2670 
2671 /*
2672 #if defined (NO_BRIGHTCOLOR) || defined (VERYBOLD)
2673 # define MONO_BOLD(x)		((x) & (RS_Bold|RS_Blink))
2674 # define MONO_BOLD_FG(x, fg)	MONO_BOLD(x)
2675 #else
2676 # define MONO_BOLD(x)						\
2677 	(((x) & (RS_Bold | RS_fgMask)) == (RS_Bold | Color_fg))
2678 # define MONO_BOLD_FG(x, fg)	(((x) & RS_Bold) && (fg) == Color_fg)
2679 #endif
2680 */
2681 /* Synchronize the macros to thai.c!!! */
2682 #ifdef NO_BRIGHTCOLOR
2683 # define MONO_BOLD(x)		((x) & (RS_Bold|RS_Blink))
2684 # define MONO_BOLD_FG(x, fg)	MONO_BOLD(x)
2685 #else	/* NO_BRIGHTCOLOR */
2686 # define MONO_BOLD(x)			\
2687 	((r->Options2 & Opt2_veryBold) ?	\
2688 	 ((x) & (RS_Bold|RS_Blink)) :			\
2689 	 (((x) & (RS_Bold | RS_fgMask)) == (RS_Bold | Color_fg))	\
2690 	)
2691 # define MONO_BOLD_FG(x, fg)	\
2692 	((r->Options2 & Opt2_veryBold) ?	\
2693 	 MONO_BOLD(x) :							\
2694 	 (((x) & RS_Bold) && (fg) == Color_fg)	\
2695 	)
2696 #endif	/* NO_BRIGHTCOLOR */
2697 
2698 
2699 #define FONT_WIDTH(X, Y)						\
2700 	(X)->per_char[(Y) - (X)->min_char_or_byte2].width
2701 #define FONT_RBEAR(X, Y)						\
2702 	(X)->per_char[(Y) - (X)->min_char_or_byte2].rbearing
2703 #define FONT_LBEAR(X, Y)						\
2704 	(X)->per_char[(Y) - (X)->min_char_or_byte2].lbearing
2705 #define IS_FONT_CHAR(X, Y)						\
2706 	((Y) >= (X)->min_char_or_byte2 && (Y) <= (X)->max_char_or_byte2)
2707 
2708 /* EXTPROTO */
2709 void
rxvt_scr_refresh(rxvt_t * r,int page,unsigned char refresh_type)2710 rxvt_scr_refresh(rxvt_t* r, int page, unsigned char refresh_type)
2711 {
2712 	unsigned char
2713 				clearfirst,	/* first character writes before cell */
2714 				clearlast,	/* last character writes beyond cell */
2715 				must_clear,	/* use drawfunc not image_drawfunc */
2716 #ifndef NO_BOLDFONT
2717 				bfont,		/* we've changed font to bold font */
2718 #endif
2719 				rvid,		/* reverse video this position */
2720 				wbyte,		/* we're in multibyte */
2721 				showcursor;	/* show the cursor */
2722 	char		morecur = 0;/* */
2723 #ifdef TTY_256COLOR
2724 	RUINT16T	fore, back;	/* desired foreground/background */
2725 #else
2726 	unsigned char
2727 				fore, back;	/* desired foreground/background */
2728 #endif
2729 	RINT16T		col, row,	/* column/row we're processing */
2730 				ocrow,		/* old cursor row */
2731 				len, wlen;	/* text length screen/buffer */
2732 	int			i,			/* tmp */
2733 				row_offset;	/* basic offset in screen structure */
2734 #ifndef NO_CURSORCOLOR
2735 	rend_t		cc1;		/* store colours at cursor position(s) */
2736 # ifdef MULTICHAR_SET
2737 	rend_t		cc2;		/* store colours at cursor position(s) */
2738 # endif
2739 #endif
2740 	XGCValues	gcvalue;	/* Graphics Context values */
2741 	XFontStruct*	wf;		/* font structure */
2742 	rend_t*		drp;		/* drawn_rend pointer */
2743 	rend_t*		srp;		/* screen-rend-pointer */
2744 	text_t*		dtp;		/* drawn-text pointer */
2745 	text_t*		stp;		/* screen-text-pointer */
2746 	char*		buffer;		/* local copy of r->h->buffer */
2747 #ifdef THAI
2748 	int			thaicol_stp_offset = 0;
2749 	int			thaicol_dtp_offset = 0;
2750 #endif	/* THAI */
2751 	/*
2752 	int			(*drawfunc) () = XDrawString;
2753 	int			(*image_drawfunc) () = XDrawImageString;
2754 	*/
2755 	int			drawfunc, image_drawfunc;
2756 	struct rxvt_hidden *h = r->h;
2757 
2758 
2759 	if (refresh_type == NO_REFRESH || !PVTS(r, page)->mapped)
2760 		return;
2761 
2762 	DBG_MSG(3, (stderr, "rxvt_scr_refresh %d ()\n", page));
2763 
2764 	/*
2765 	** A: set up vars
2766 	*/
2767 #ifdef XFT_SUPPORT
2768 	if ((r->Options & Opt_xft) && PVTS(r, page)->xftvt)	{
2769 		drawfunc = XFT_DRAW_STRING_8;
2770 		image_drawfunc = XFT_DRAW_IMAGE_STRING_8;
2771 	}
2772 	else
2773 #endif
2774 	{
2775 		drawfunc = X11_DRAW_STRING_8;
2776 		image_drawfunc = X11_DRAW_IMAGE_STRING_8;
2777 	}
2778 
2779 	clearfirst = clearlast = must_clear = wbyte = 0;
2780 #ifndef NO_BOLDFONT
2781 	bfont = 0;
2782 #endif
2783 
2784 	if (h->currmaxcol < r->TermWin.ncol) {
2785 		h->currmaxcol = r->TermWin.ncol;
2786 		h->buffer = rxvt_realloc(h->buffer, sizeof(char) * (h->currmaxcol + 1));
2787 	}
2788 	buffer = h->buffer;
2789 	h->refresh_count = 0;
2790 
2791 	row_offset = SVLINES - VSTART;
2792 #ifdef XFT_SUPPORT
2793 	if (!((r->Options & Opt_xft) && r->TermWin.xftfont))
2794 #endif
2795 	{
2796 		/* always go back to the base font - it's much safer */
2797 		XSetFont(r->Xdisplay, r->TermWin.gc, r->TermWin.font->fid);
2798 		wf = r->TermWin.font;
2799 	}
2800 
2801 	if ((refresh_type & REFRESH_BOUNDS)) {
2802 		clearfirst = clearlast = 1;
2803 		h->refresh_type &= ~REFRESH_BOUNDS;
2804 	}
2805 #if defined(BACKGROUND_IMAGE)
2806 	must_clear |= (PVTS(r, page)->bg.pixmap != None);
2807 #endif
2808 #if defined(TRANSPARENT)
2809 	must_clear |= ((r->Options & Opt_transparent) && h->am_transparent);
2810 #endif
2811 	/* is there an old outline cursor on screen? */
2812 	ocrow = h->oldcursor.row;
2813 
2814 	/* set base colours to avoid check in "single glyph writing"
2815 	** below
2816 	*/
2817 	gcvalue.foreground = r->PixColors[Color_fg];
2818 	gcvalue.background = r->PixColors[Color_bg];
2819 
2820 
2821 	/*
2822 	** B: reverse any characters which are selected
2823 	*/
2824 	rxvt_scr_reverse_selection(r, page);
2825 
2826 
2827 	/*
2828 	** C: set the cursor character(s)
2829 	*/
2830 	{
2831 		unsigned char	setoldcursor;
2832 		rend_t			ccol1,	/* Cursor colour */
2833 						ccol2;	/* Cursor colour2 */
2834 
2835 		showcursor = (PSCR(r, page).flags & Screen_VisibleCursor);
2836 #ifdef CURSOR_BLINK
2837 		if (r->h->hidden_cursor)
2838 			showcursor = 0;
2839 #endif
2840 		if (showcursor && r->TermWin.focus) {
2841 			int		currow = CURROW + SVLINES;
2842 			srp = &(PSCR(r, page).rend[currow][CURCOL]);
2843 
2844 #ifdef THAI
2845 			if ((r->Options & Opt_thai) &&
2846 				FONT_WIDTH(r->TermWin.font, PSCR(r, page).text[currow][CURCOL]) <= 0)
2847 				*srp ^= RS_Bold;
2848 			else if (!(r->Options & Opt_thai))
2849 #endif	/* THAI */
2850 			*srp ^= RS_RVid;
2851 
2852 #ifndef NO_CURSORCOLOR
2853 			cc1 = *srp & (RS_fgMask | RS_bgMask);
2854 			if (XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_cursor))
2855 				ccol1 = Color_cursor;
2856 			else
2857 #ifdef CURSOR_COLOR_IS_RENDITION_COLOR
2858 				ccol1 = GET_FGCOLOR(
2859 							PVTS(r, page)->drawn_rend[CURROW][CURCOL]);
2860 				/*
2861 				ccol1 = GET_FGCOLOR(PVTS(r, page)->rstyle);
2862 				*/
2863 #else
2864 				ccol1 = Color_fg;
2865 #endif
2866 			if (XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_cursor))
2867 				ccol2 = Color_cursor2;
2868 			else
2869 #ifdef CURSOR_COLOR_IS_RENDITION_COLOR
2870 # ifdef SIMULATE_LINUX_CONSOLE_CURSOR_COLOR
2871 				ccol2 = GET_FGCOLOR(PVTS(r, page)->drawn_rend[CURROW][CURCOL]);
2872 # else
2873 				ccol2 = GET_BGCOLOR(PVTS(r, page)->drawn_rend[CURROW][CURCOL]);
2874 # endif	/* SIMULATE_LINUX_CONSOLE_CURSOR_COLOR */
2875 				/*
2876 				ccol2 = GET_BGCOLOR(PVTS(r, page)->rstyle);
2877 				*/
2878 #else
2879 				ccol2 = Color_bg;
2880 #endif
2881 			*srp = SET_FGCOLOR(*srp, ccol1);
2882 			*srp = SET_BGCOLOR(*srp, ccol2);
2883 #endif
2884 #ifdef MULTICHAR_SET
2885 			if (IS_MULTI1(*srp)) {
2886 				if (CURCOL < r->TermWin.ncol - 2 && IS_MULTI2(*++srp))
2887 					morecur = 1;
2888 			}
2889 			else if (IS_MULTI2(*srp)) {
2890 				if (CURCOL > 0 && IS_MULTI1(*--srp))
2891 					morecur = -1;
2892 			}
2893 			if (morecur) {
2894 				*srp ^= RS_RVid;
2895 # ifndef NO_CURSORCOLOR
2896 				cc2 = *srp & (RS_fgMask | RS_bgMask);
2897 				*srp = SET_FGCOLOR(*srp, ccol1);
2898 				*srp = SET_BGCOLOR(*srp, ccol2);
2899 # endif
2900 			}
2901 #endif
2902 		}
2903 
2904 		/* make sure no outline cursor is left around */
2905 		setoldcursor = 0;
2906 		if (ocrow != -1) {
2907 			if (CURROW + VSTART != ocrow ||
2908 				CURCOL != h->oldcursor.col) {
2909 			if (ocrow < r->TermWin.nrow &&
2910 				h->oldcursor.col < r->TermWin.ncol) {
2911 				PVTS(r, page)->drawn_rend[ocrow][h->oldcursor.col] ^=
2912 					(RS_RVid | RS_Uline);
2913 #ifdef MULTICHAR_SET
2914 				if (h->oldcursormulti) {
2915 					col = h->oldcursor.col + h->oldcursormulti;
2916 					if (col < r->TermWin.ncol)
2917 						PVTS(r, page)->drawn_rend[ocrow][col] ^=
2918 							(RS_RVid | RS_Uline);
2919 				}
2920 #endif
2921 			}
2922 			if (r->TermWin.focus || !showcursor)
2923 				h->oldcursor.row = -1;
2924 			else
2925 				setoldcursor = 1;
2926 			}
2927 		}
2928 		else if (!r->TermWin.focus)
2929 			setoldcursor = 1;
2930 		if (setoldcursor) {
2931 			if (CURROW + VSTART >= r->TermWin.nrow)
2932 				h->oldcursor.row = -1;
2933 			else {
2934 				h->oldcursor.row = CURROW + VSTART;
2935 				h->oldcursor.col = CURCOL;
2936 #ifdef MULTICHAR_SET
2937 				h->oldcursormulti = morecur;
2938 #endif
2939 			}
2940 		}
2941 	}
2942 	/* End of C */
2943 
2944 
2945 #ifndef NO_SLOW_LINK_SUPPORT
2946 	/*
2947 	** D: CopyArea pass - very useful for slower links
2948 	**	This has been deliberately kept simple.
2949 	*/
2950 	i = PVTS(r, page)->num_scr;
2951 	if (refresh_type == FAST_REFRESH &&
2952 		h->num_scr_allow &&
2953 		i &&
2954 		abs(i) < r->TermWin.nrow &&
2955 		!must_clear) {
2956 		RINT16T		 nits;
2957 		int			 j;
2958 		rend_t		 *drp2;
2959 		text_t		 *dtp2;
2960 
2961 		j = r->TermWin.nrow;
2962 		wlen = len = -1;
2963 		row = i > 0 ? 0 : j - 1;
2964 		for (; j-- >= 0; row += (i > 0 ? 1 : -1)) {
2965 			if (row + i >= 0 &&
2966 				row + i < r->TermWin.nrow &&
2967 				row + i != ocrow) {
2968 				stp = PSCR(r, page).text[row + row_offset];
2969 				srp = PSCR(r, page).rend[row + row_offset];
2970 				dtp = PVTS(r, page)->drawn_text[row];
2971 				dtp2 = PVTS(r, page)->drawn_text[row + i];
2972 				drp = PVTS(r, page)->drawn_rend[row];
2973 				drp2 = PVTS(r, page)->drawn_rend[row + i];
2974 				for (nits = 0, col = r->TermWin.ncol; col--; )
2975 					if (stp[col] != dtp2[col] ||
2976 						srp[col] != drp2[col])
2977 						nits--;
2978 					else if (stp[col] != dtp[col] ||
2979 						srp[col] != drp[col])
2980 						nits++;
2981 				if (nits > 8) {	/* XXX: arbitrary choice */
2982 					for (col = r->TermWin.ncol; col--; ) {
2983 						*dtp++ = *dtp2++;
2984 						*drp++ = *drp2++;
2985 					}
2986 					if (len == -1)
2987 					len = row;
2988 					wlen = row;
2989 					continue;
2990 				}
2991 			}
2992 
2993 			if (len != -1) {
2994 			/* also comes here at end if needed because of >= above */
2995 				if (wlen < len)
2996 					SWAP_IT(wlen, len, int);
2997 				DBG_MSG(2,(stderr, "rxvt_scr_refresh %d (): XCopyArea: %d -> %d (height: %d)\n", page, len + i, len, wlen - len + 1));
2998 				XCopyArea(r->Xdisplay, PVTS(r, page)->vt,
2999 					PVTS(r, page)->vt, r->TermWin.gc,
3000 					0, Row2Pixel(len + i),
3001 					TWIN_WIDTH(r),
3002 					(unsigned int)Height2Pixel(wlen-len+1),
3003 					0, Row2Pixel(len));
3004 				len = -1;
3005 			}
3006 		}
3007 	}	/* End of D */
3008 #endif	/* !NO_SLOW_LINK_SUPPORT */
3009 
3010 
3011 	/*
3012 	** E: main pass across every character
3013 	*/
3014 	for (row = 0; row < r->TermWin.nrow; row++) {
3015 		unsigned char	clear_next = 0;
3016 		int				j,
3017 						/* x offset for start of drawing (font) */
3018 						xpixel,
3019 						/* y offset for top of drawing */
3020 						ypixelc;
3021 		unsigned long	gcmask;	 /* Graphics Context mask */
3022 #ifdef THAI
3023 		char*			thai_update = NULL;
3024 #endif	/* THAI */
3025 
3026 
3027 		stp = PSCR(r, page).text[row + row_offset];
3028 		srp = PSCR(r, page).rend[row + row_offset];
3029 		dtp = PVTS(r, page)->drawn_text[row];
3030 		drp = PVTS(r, page)->drawn_rend[row];
3031 
3032 
3033 #ifdef THAI
3034 		if (r->Options & Opt_thai)	{
3035 			/* possible integer overflow? */
3036 			assert (r->TermWin.ncol > 0);
3037 			thai_update = (char*) rxvt_malloc (r->TermWin.ncol);
3038 			/* compare drawn_text and screen.text and check which to
3039 			** update */
3040 			ThaiUpdateMap (PSCR(r, page).text[row + row_offset],
3041 				PVTS(r, page)->drawn_text[row],
3042 				PSCR(r, page).rend[row + row_offset],
3043 				PVTS(r, page)->drawn_rend[row],
3044 				thai_update, r->TermWin.ncol);
3045 			/* TODO: Change this algo to scalefont compatible */
3046 			thaicol_stp_offset = 0; /* records how many col deficit */
3047 			thaicol_dtp_offset = r->TermWin.ncol - Thai_ColMaxPaint (dtp, r->TermWin.ncol);
3048 			/* clean strings before redraw */
3049 			for (col = 0; col < r->TermWin.ncol; col ++)	{
3050 				if (!ThaiIsMiddleLineCh (stp[col]))
3051 					thaicol_stp_offset ++;
3052 			}
3053 			ypixelc = (int)Row2Pixel(row);
3054 			if (thaicol_stp_offset > thaicol_dtp_offset)	{
3055 				CLEAR_CHARS(
3056 					Col2Pixel (r->TermWin.ncol - thaicol_stp_offset),
3057 					ypixelc,
3058 					thaicol_stp_offset);
3059 			}
3060 		}
3061 #endif	/* THAI */
3062 
3063 #ifndef NO_PIXEL_DROPPING_AVOIDANCE
3064 		/*
3065 		** E1: pixel dropping avoidance.  Do this before the main
3066 		** refresh on the line. Require a refresh where pixels may
3067 		** have been dropped into our area by a neighbour character
3068 		** which has now changed
3069 		** TODO: this could be integrated into E2 but might be too
3070 		** messy
3071 		*/
3072 		for (col = 0; col < r->TermWin.ncol; col++) {
3073 			unsigned char	is_font_char, is_same_char;
3074 			text_t			t;
3075 
3076 			t = dtp[col];
3077 			is_same_char = (t == stp[col] && drp[col] == srp[col]);
3078 			if (!clear_next &&
3079 				(is_same_char || t == 0 || t == ' '))
3080 				/* screen cleared elsewhere */
3081 				continue;
3082 
3083 			if (clear_next) {
3084 				/* previous char caused change here */
3085 				clear_next = 0;
3086 				dtp[col] = 0;
3087 
3088 				/* don't cascade into next char */
3089 				if (is_same_char)
3090 					continue;
3091 			}
3092 			j = MONO_BOLD(drp[col]) ? 1 : 0;
3093 # ifndef NO_BOLDFONT
3094 			wf = (j && r->TermWin.bfont) ?
3095 						r->TermWin.bfont : r->TermWin.font;
3096 # endif
3097 
3098 			/*
3099 			** TODO: consider if anything special needs to happen
3100 			** with:
3101 			** #if defined(MULTICHAR_SET) &&
3102 			** !defined(NO_BOLDOVERSTRIKE_MULTI)
3103 			*/
3104 			is_font_char = (wf->per_char && IS_FONT_CHAR(wf, t)) ? 1:0;
3105 			if (!is_font_char || FONT_LBEAR(wf, t) < 0) {
3106 				if (col == 0)
3107 					clearfirst = 1;
3108 				else
3109 					dtp[col - 1] = 0;
3110 			}
3111 			if (!is_font_char ||
3112 				(FONT_WIDTH(wf, t) < (FONT_RBEAR(wf, t) + j))) {
3113 				if (col == r->TermWin.ncol - 1)
3114 					clearlast = 1;
3115 				else
3116 					clear_next = 1;
3117 			}
3118 		}
3119 #endif	/* NO_PIXEL_DROPPING_AVOIDANCE */
3120 		/* End of E1 */
3121 
3122 
3123 		/*
3124 		** E2: OK, now the real pass
3125 		*/
3126 		ypixelc = (int)Row2Pixel(row);
3127 
3128 		for (col = 0; col < r->TermWin.ncol; col++) {
3129 							/* current font size != base font size */
3130 			unsigned char	fontdiff,
3131 							/* proportional font used */
3132 							fprop;
3133 							/* rendition value */
3134 			rend_t			rend;
3135 
3136 			/* compare new text with old - if exactly the same then
3137 			** continue
3138 			*/
3139 			/* screen rendition (target rendtion) */
3140 			rend = srp[col];
3141 			if (
3142 #ifdef THAI
3143 				((r->Options & Opt_thai) && !thai_update[col]) ||
3144 				(!(r->Options & Opt_thai) &&
3145 #endif	/* THAI */
3146 				/* Must match characters to skip. */
3147 				(stp[col] == dtp[col] &&
3148 				/* Either rendition the same or   */
3149 				  (rend == drp[col] ||
3150 				/* space w/ no background change  */
3151 					(stp[col] == ' ' &&
3152 						GET_BGATTR(rend) == GET_BGATTR(drp[col]))))
3153 #ifdef THAI
3154 				)	/* need a match of ( */
3155 #endif	/* THAI */
3156 				) {	/* if */
3157 				if (!IS_MULTI1(rend))
3158 					continue;
3159 #ifdef MULTICHAR_SET
3160 				else {
3161 					/* first byte is Kanji so compare second bytes */
3162 					if (stp[col + 1] == dtp[col + 1]) {
3163 					/* assume no corrupt characters on the screen */
3164 						col++;
3165 					continue;
3166 					}
3167 				}
3168 #endif
3169 			}
3170 			/* redraw one or more characters */
3171 
3172 			fontdiff = 0;
3173 			len = 0;
3174 #ifdef THAI
3175 			if (!(r->Options & Opt_thai))
3176 #endif	/* THAI */
3177 			buffer[len++] = dtp[col] = stp[col];
3178 			drp[col] = rend;
3179 #ifdef THAI
3180 			if (r->Options & Opt_thai)
3181 				xpixel = ThaiCol2Pixel (r, col, PSCR(r, page).text[row + row_offset]);
3182 			else
3183 #endif	/* THAI */
3184 			xpixel = Col2Pixel(col);
3185 
3186 			/*
3187 			** Find out the longest string we can write out at once
3188 			*/
3189 #ifndef NO_BOLDFONT
3190 			if (MONO_BOLD(rend) && r->TermWin.bfont != NULL)
3191 				fprop = (r->TermWin.propfont & PROPFONT_BOLD);
3192 			else
3193 #endif
3194 				fprop = (r->TermWin.propfont & PROPFONT_NORMAL);
3195 
3196 #ifdef MULTICHAR_SET
3197 			if (IS_MULTI1(rend) &&
3198 				col < r->TermWin.ncol - 1 && IS_MULTI2(srp[col + 1])) {
3199 				if (!wbyte && r->TermWin.mfont) {
3200 					wbyte = 1;
3201 					XSetFont(r->Xdisplay, r->TermWin.gc,
3202 						 r->TermWin.mfont->fid);
3203 					fontdiff = (r->TermWin.propfont & PROPFONT_MULTI);
3204 #ifdef XFT_SUPPORT
3205 					if ((r->Options & Opt_xft) && PVTS(r, page)->xftvt){
3206 						drawfunc = XFT_DRAW_STRING_16;
3207 						image_drawfunc = XFT_DRAW_IMAGE_STRING_16;
3208 					}
3209 					else
3210 #endif
3211 					{
3212 						drawfunc = X11_DRAW_STRING_16;
3213 						image_drawfunc = X11_DRAW_IMAGE_STRING_16;
3214 					}
3215 				}
3216 
3217 				if (r->TermWin.mfont == NULL) {
3218 					buffer[0] = buffer[1] = ' ';
3219 					len = 2;
3220 					col++;
3221 				}
3222 				else {
3223 					/* double stepping - we're in multibyte font mode */
3224 					for (; ++col < r->TermWin.ncol;) {
3225 						/* XXX: could check sanity on 2nd byte */
3226 						dtp[col] = stp[col];
3227 						drp[col] = srp[col];
3228 						buffer[len++] = stp[col];
3229 						col++;
3230 						/* proportional multibyte font mode */
3231 						if (fprop)
3232 							break;
3233 						if ((col == r->TermWin.ncol) ||
3234 							(srp[col] != rend))
3235 							break;
3236 						if ((stp[col] == dtp[col]) &&
3237 							(srp[col] == drp[col]) &&
3238 							(stp[col + 1] == dtp[col + 1]))
3239 							break;
3240 						if (len == h->currmaxcol)
3241 							break;
3242 						dtp[col] = stp[col];
3243 						drp[col] = srp[col];
3244 						buffer[len++] = stp[col];
3245 					}
3246 					col--;
3247 				}
3248 
3249 				if (buffer[0] & 0x80)
3250 					(h->multichar_decode)(buffer, len);
3251 				wlen = len / 2;
3252 			}
3253 			else {
3254 				if (rend & RS_multi1) {
3255 					/* corrupt character - you're outta there */
3256 					rend &= ~RS_multiMask;
3257 					drp[col] = rend; /* TODO check: may also want */
3258 					dtp[col] = ' ';	/* to poke into stp/srp	  */
3259 					buffer[0] = ' ';
3260 				}
3261 				if (wbyte) {
3262 					wbyte = 0;
3263 #ifdef XFT_SUPPORT
3264 					if (!((r->Options & Opt_xft) && r->TermWin.xftfont))
3265 #endif
3266 					XSetFont(r->Xdisplay, r->TermWin.gc,
3267 						r->TermWin.font->fid);
3268 #ifdef XFT_SUPPORT
3269 					if ((r->Options & Opt_xft) && PVTS(r, page)->xftvt){
3270 						drawfunc = XFT_DRAW_STRING_8;
3271 						image_drawfunc = XFT_DRAW_IMAGE_STRING_8;
3272 					}
3273 					else
3274 #endif
3275 					{
3276 						drawfunc = X11_DRAW_STRING_8;
3277 						image_drawfunc = X11_DRAW_IMAGE_STRING_8;
3278 					}
3279 				}	/* if (wbyte) */
3280 #else
3281 			{
3282 #endif
3283 				if (!fprop) {
3284 					/* single stepping - `normal' mode */
3285 					for (i = 0; ++col < r->TermWin.ncol - 1;) {
3286 						if (rend != srp[col])
3287 							break;
3288 						buffer[len++] = stp[col];
3289 						if ((stp[col] != dtp[col]) ||
3290 							(srp[col] != drp[col])) {
3291 							if (must_clear && (i++ > (len / 2)))
3292 								break;
3293 							dtp[col] = stp[col];
3294 							drp[col] = srp[col];
3295 							i = 0;
3296 						}
3297 						else if (must_clear ||
3298 							(stp[col] != ' ' && ++i > 32))
3299 							break;
3300 					}	/* for */
3301 					col--;	/* went one too far.  move back */
3302 					len -= i;	/* dump any matching trailing chars */
3303 				} /* if (!fprop) */
3304 				wlen = len;
3305 			}
3306 			buffer[len] = '\0';
3307 
3308 			/*
3309 			** Determine the attributes for the string
3310 			*/
3311 			fore = GET_FGCOLOR(rend);
3312 			back = GET_BGCOLOR(rend);
3313 			rend = GET_ATTR(rend);
3314 
3315 			switch (rend & RS_fontMask) {
3316 			case RS_acsFont:
3317 				for (i = 0; i < len; i++)
3318 					if (buffer[i] == 0x5f)
3319 						buffer[i] = 0x7f;
3320 					else if (buffer[i] > 0x5f && buffer[i] < 0x7f)
3321 						buffer[i] -= 0x5f;
3322 				break;
3323 			case RS_ukFont:
3324 				for (i = 0; i < len; i++)
3325 					if (buffer[i] == '#')
3326 						buffer[i] = 0x1e;	/* pound sign */
3327 				break;
3328 			}
3329 
3330 			rvid = (rend & RS_RVid) ? 1 : 0;
3331 #ifdef OPTION_HC
3332 			if (!rvid && (rend & RS_Blink)) {
3333 				if (XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_HC) &&
3334 					r->PixColors[fore] != r->PixColors[Color_HC] &&
3335 					r->PixColors[back] != r->PixColors[Color_HC])
3336 					back = Color_HC;
3337 				else
3338 					rvid = !rvid;	/* fall back */
3339 			}
3340 #endif
3341 
3342 			if (
3343 #ifdef THAI
3344 				(rvid && (r->Options & Opt_thai) &&
3345 				 (FONT_WIDTH(wf, stp[col]) > 0)) ||
3346 				(!(r->Options & Opt_thai) &&
3347 #endif	/* THAI */
3348 				rvid
3349 #ifdef THAI
3350 				)	/* match the ( */
3351 #endif	/* THAI */
3352 				)	{
3353 
3354 #ifdef TTY_256COLOR
3355 				SWAP_IT(fore, back, RUINT16T);
3356 #else
3357 				SWAP_IT(fore, back, unsigned char);
3358 #endif
3359 #ifndef NO_BOLD_UNDERLINE_REVERSE
3360 				if (XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_RV)
3361 # ifndef NO_CURSORCOLOR
3362 					&& (!ISSET_PIXCOLOR(h, Color_cursor) ||
3363 					r->PixColors[back] != r->PixColors[Color_cursor])
3364 # endif
3365 					&& r->PixColors[fore] != r->PixColors[Color_RV])
3366 					back = Color_RV;
3367 #endif
3368 			}
3369 			gcmask = 0;
3370 			if (back != Color_bg) {
3371 				gcvalue.background = r->PixColors[back];
3372 				gcmask = GCBackground;
3373 			}
3374 			if (fore != Color_fg) {
3375 				gcvalue.foreground = r->PixColors[fore];
3376 				gcmask |= GCForeground;
3377 			}
3378 #ifndef NO_BOLD_UNDERLINE_REVERSE
3379 			else if (rend & RS_Bold) {
3380 				if (XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_BD) &&
3381 					r->PixColors[fore] != r->PixColors[Color_BD] &&
3382 					r->PixColors[back] != r->PixColors[Color_BD]) {
3383 					gcvalue.foreground = r->PixColors[Color_BD];
3384 					gcmask |= GCForeground;
3385 					if (!(r->Options2 & Opt2_veryBold))
3386 						rend &= ~RS_Bold;	/* we've taken care of it */
3387 				}
3388 			}
3389 			else if (rend & RS_Uline) {
3390 				if (XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_UL) &&
3391 					r->PixColors[fore] != r->PixColors[Color_UL] &&
3392 					r->PixColors[back] != r->PixColors[Color_UL]) {
3393 					gcvalue.foreground = r->PixColors[Color_UL];
3394 					gcmask |= GCForeground;
3395 					rend &= ~RS_Uline;	/* we've taken care of it */
3396 				}
3397 			}
3398 #endif
3399 			if (gcmask)
3400 				XChangeGC(r->Xdisplay, r->TermWin.gc, gcmask, &gcvalue);
3401 #ifndef NO_BOLDFONT
3402 			if (!wbyte && MONO_BOLD_FG(rend, fore) &&
3403 				r->TermWin.bfont != NULL) {
3404 				bfont = 1;
3405 # ifdef XFT_SUPPORT
3406 				if ((r->Options & Opt_xft) && r->TermWin.xftfont)
3407 					rxvt_switch_bold_font (r);
3408 				else
3409 # endif
3410 				XSetFont(r->Xdisplay, r->TermWin.gc,
3411 					r->TermWin.bfont->fid);
3412 				fontdiff = (r->TermWin.propfont & PROPFONT_BOLD);
3413 				rend &= ~RS_Bold;	/* we've taken care of it */
3414 			}
3415 			else if (bfont) {
3416 				bfont = 0;
3417 # ifdef XFT_SUPPORT
3418 				if ((r->Options & Opt_xft) && r->TermWin.xftfont)
3419 					rxvt_restore_bold_font (r);
3420 				else
3421 # endif
3422 				XSetFont(r->Xdisplay, r->TermWin.gc,
3423 					r->TermWin.font->fid);
3424 			}
3425 #endif
3426 
3427 			/*
3428 			** Actually do the drawing of the string here
3429 			*/
3430 			if (back == Color_bg && must_clear) {
3431 #ifdef THAI
3432 				if ((r->Options & Opt_thai) &&
3433 					FONT_WIDTH(wf, stp[col]) > 0)	{
3434 					CLEAR_CHARS(xpixel, ypixelc, len);
3435 				}
3436 				else if (!(r->Options & Opt_thai))
3437 #endif	/* THAI */
3438 				{
3439 					CLEAR_CHARS(xpixel, ypixelc, len);
3440 				}
3441 				for (i = 0; i < len; i++)
3442 					/* don't draw empty strings */
3443 					if (buffer[i] != ' ') {
3444 						rxvt_scr_draw_string (r, page, xpixel, ypixelc, buffer, wlen, drawfunc, fore, back);
3445 						break;
3446 					}
3447 			}
3448 			else if (fprop || fontdiff) {
3449 				/* single glyph writing */
3450 				unsigned long   pixel;
3451 
3452 				pixel = gcvalue.foreground;
3453 				gcvalue.foreground = gcvalue.background;
3454 				XChangeGC(r->Xdisplay, r->TermWin.gc, GCForeground, &gcvalue);
3455 				rxvt_fill_rectangle (r, page, xpixel, ypixelc,
3456 					(unsigned int) Width2Pixel(len),
3457 					(unsigned int) (Height2Pixel(1)
3458 					/* - r->TermWin.lineSpace */));
3459 				gcvalue.foreground = pixel;
3460 				XChangeGC(r->Xdisplay, r->TermWin.gc, GCForeground, &gcvalue);
3461 				rxvt_scr_draw_string (r, page, xpixel, ypixelc, buffer, wlen, drawfunc, fore, back);
3462 			}
3463 			else	{
3464 				rxvt_scr_draw_string (r, page, xpixel, ypixelc, buffer, wlen, image_drawfunc, fore, back);
3465 			}
3466 
3467 #ifndef NO_BOLDOVERSTRIKE
3468 # ifdef NO_BOLDOVERSTRIKE_MULTI
3469 			if (!wbyte)
3470 # endif
3471 			if (MONO_BOLD_FG(rend, fore))	{
3472 				rxvt_scr_draw_string (r, page, xpixel + 1, ypixelc, buffer, wlen, drawfunc, fore, back);
3473 			}
3474 #endif
3475 			if (rend & RS_Uline)	{
3476 #ifdef XFT_SUPPORT
3477 				if ((r->Options & Opt_xft) && PVTS(r, page)->xftvt)	{
3478 					if (r->TermWin.xftfont->descent > 1)
3479 						XDrawLine(r->Xdisplay, drawBuffer,
3480 							r->TermWin.gc,
3481 							xpixel,
3482 							ypixelc + r->TermWin.xftfont->ascent + 1,
3483 							xpixel + Width2Pixel(len) - 1,
3484 							ypixelc + r->TermWin.xftfont->ascent + 1);
3485 				}
3486 				else
3487 #endif
3488 				if (r->TermWin.font->descent > 1)
3489 					XDrawLine(r->Xdisplay, drawBuffer, r->TermWin.gc,
3490 						xpixel,
3491 						ypixelc + r->TermWin.font->ascent + 1,
3492 						xpixel + Width2Pixel(len) - 1,
3493 						ypixelc + r->TermWin.font->ascent + 1);
3494 			}
3495 
3496 			if (gcmask) {	/* restore normal colours */
3497 				gcvalue.foreground = r->PixColors[Color_fg];
3498 				gcvalue.background = r->PixColors[Color_bg];
3499 				XChangeGC(r->Xdisplay, r->TermWin.gc, gcmask, &gcvalue);
3500 			}
3501 		}			/* for (col....) */
3502 		/* End of E2 */
3503 	}				/* for (row....) */
3504 	/* End of E */
3505 
3506 #ifdef THAI
3507 	if (r->Options & Opt_thai)	{
3508 		for (row = 0; row < r->TermWin.nrow; row ++)	{
3509 			stp = PSCR(r, page).text[row + row_offset];
3510 			srp = PSCR(r, page).rend[row + row_offset];
3511 			dtp = PVTS(r, page)->drawn_text[row];
3512 			drp = PVTS(r, page)->drawn_rend[row];
3513 
3514 			for (col = 0; col < r->TermWin.ncol; col++)	{
3515 				dtp[col] = stp[col];
3516 				drp[col] = srp[col];
3517 			}
3518 		}
3519 	}
3520 #endif	/* THAI */
3521 
3522 
3523 	/*
3524 	** G: cleanup cursor and display outline cursor in necessary
3525 	*/
3526 	if (showcursor) {
3527 		if (r->TermWin.focus) {
3528 			int		currow = CURROW + SVLINES;
3529 			srp = &(PSCR(r, page).rend[currow][CURCOL]);
3530 #ifdef THAI
3531 			if ((r->Options & Opt_thai) &&
3532 				FONT_WIDTH(wf, PSCR(r, page).text[currow][CURCOL]) <= 0)
3533 				*srp ^= RS_Bold;
3534 			else if (!(r->Options & Opt_thai))
3535 #endif	/* THAI */
3536 			*srp ^= RS_RVid;
3537 
3538 #ifndef NO_CURSORCOLOR
3539 			*srp = (*srp & ~(RS_fgMask | RS_bgMask)) | cc1;
3540 #endif
3541 #ifdef MULTICHAR_SET
3542 			if (morecur) {
3543 				srp += morecur;
3544 				*srp ^= RS_RVid;
3545 # ifndef NO_CURSORCOLOR
3546 				*srp = (*srp & ~(RS_fgMask | RS_bgMask)) | cc2;
3547 # endif
3548 			}
3549 #endif
3550 		}
3551 		else if (h->oldcursor.row >= 0) {
3552 #ifndef NO_CURSORCOLOR
3553 			unsigned long   gcmask;	/* Graphics Context mask */
3554 
3555 			gcmask = 0;
3556 			if (XDEPTH > 2 && ISSET_PIXCOLOR(h, Color_cursor)) {
3557 				gcvalue.foreground = r->PixColors[Color_cursor];
3558 				gcmask = GCForeground;
3559 				XChangeGC(r->Xdisplay, r->TermWin.gc, gcmask, &gcvalue);
3560 					gcvalue.foreground = r->PixColors[Color_fg];
3561 			}
3562 #endif
3563 
3564 #ifdef THAI
3565 			if (r->Options & Opt_thai)	{
3566 				XDrawRectangle(r->Xdisplay, drawBuffer, r->TermWin.gc,
3567 					ThaiCol2Pixel (r, h->oldcursor.col + morecur,
3568 						PSCR(r, page).text[CURROW + SVLINES]),
3569 					Row2Pixel(h->oldcursor.row),
3570 					(unsigned int)(Width2Pixel(1 + (morecur?1:0)) - 1),
3571 					(unsigned int)(Height2Pixel(1)
3572 					/* - r->TermWin.lineSpace*/ - 1));
3573 			}
3574 			else
3575 #endif	/* THAI */
3576 			{
3577 				XDrawRectangle(r->Xdisplay, drawBuffer, r->TermWin.gc,
3578 					Col2Pixel(h->oldcursor.col + morecur),
3579 					Row2Pixel(h->oldcursor.row),
3580 					(unsigned int)(Width2Pixel(1 + (morecur?1:0)) - 1),
3581 					(unsigned int)(Height2Pixel(1)
3582 					/* - r->TermWin.lineSpace*/ - 1));
3583 			}
3584 
3585 #ifndef NO_CURSORCOLOR
3586 			if (gcmask)		/* restore normal colours */
3587 				XChangeGC(r->Xdisplay, r->TermWin.gc, gcmask, &gcvalue);
3588 #endif
3589 		}
3590 	}
3591 	/* End of G */
3592 
3593 
3594 	/*
3595 	** H: cleanup selection
3596 	*/
3597 	rxvt_scr_reverse_selection(r, page);
3598 
3599 
3600 	/*
3601 	** I: other general cleanup
3602 	*/
3603 	/*
3604 	** clear the whole screen height, note that width == 0 is treated
3605 	** specially by XClearArea
3606 	*/
3607 	if (clearfirst && r->TermWin.int_bwidth)
3608 		rxvt_clear_area (r, page, 0, 0,
3609 			(unsigned int)r->TermWin.int_bwidth, VT_HEIGHT(r));
3610 	/*
3611 	** clear the whole screen height, note that width == 0 is treated
3612 	** specially by XClearArea
3613 	*/
3614 	if (clearlast && r->TermWin.int_bwidth)
3615 		rxvt_clear_area (r, page,
3616 			TWIN_WIDTH(r) + r->TermWin.int_bwidth, 0,
3617 			(unsigned int)r->TermWin.int_bwidth, VT_HEIGHT(r));
3618 
3619 	if (refresh_type & SMOOTH_REFRESH)
3620 		XSync(r->Xdisplay, False);
3621 
3622 	PVTS(r, page)->num_scr = 0;
3623 	h->num_scr_allow = 1;
3624 	h->want_refresh = 0;	/* screen is current */
3625 }
3626 
3627 
3628 #undef X11_DRAW_STRING_8
3629 #undef X11_DRAW_STRING_16
3630 #undef X11_DRAW_IMAGE_STRING_8
3631 #undef X11_DRAW_IMAGE_STRING_16
3632 #undef XFT_DRAW_STRING_8
3633 #undef XFT_DRAW_STRING_16
3634 #undef XFT_DRAW_STRING_32
3635 #undef XFT_DRAW_STRING_UTF8
3636 
3637 /* ------------------------------------------------------------------------- */
3638 
3639 
3640 /* EXTPROTO */
3641 void
3642 rxvt_scr_clear(rxvt_t* r, int page)
3643 {
3644 	if (!PVTS(r, page)->mapped)
3645 		return;
3646 
3647 	r->h->num_scr_allow = 0;
3648 	r->h->want_refresh = 1;
3649 #ifdef TRANSPARENT
3650 	if (r->Options & Opt_transparent)	{
3651 		if (r->TermWin.parent != None)
3652 			XClearWindow(r->Xdisplay, r->TermWin.parent);
3653 	}
3654 #endif
3655 	XClearWindow(r->Xdisplay, PVTS(r, page)->vt);
3656 }
3657 
3658 /* ------------------------------------------------------------------------- */
3659 /* INTPROTO */
3660 void
3661 rxvt_scr_reverse_selection(rxvt_t* r, int page)
3662 {
3663 	int			 i, col, row, end_row;
3664 	rend_t		 *srp;
3665 
3666 	if (SEL(r).op &&
3667 		SEL(r).vt == page &&
3668 		PVTS(r, page)->current_screen == SEL(r).screen) {
3669 		end_row = SVLINES - VSTART;
3670 
3671 		i = SEL(r).beg.row + SVLINES;
3672 		row = SEL(r).end.row + SVLINES;
3673 
3674 		if (i >= end_row)
3675 			col = SEL(r).beg.col;
3676 		else {
3677 			col = 0;
3678 			i = end_row;
3679 		}
3680 
3681 		end_row += r->TermWin.nrow;
3682 		for (; i < row && i < end_row; i++, col = 0)
3683 			for (srp = PSCR(r, page).rend[i]; col < r->TermWin.ncol; col++)
3684 #ifndef OPTION_HC
3685 				srp[col] ^= RS_RVid;
3686 #else
3687 				srp[col] ^= RS_Blink;
3688 #endif
3689 		if (i == row && i < end_row)
3690 			for (srp = PSCR(r, page).rend[i]; col < SEL(r).end.col; col++)
3691 #ifndef OPTION_HC
3692 				srp[col] ^= RS_RVid;
3693 #else
3694 				srp[col] ^= RS_Blink;
3695 #endif
3696 	}
3697 }
3698 
3699 /* ------------------------------------------------------------------------- */
3700 /*
3701  * Dump the whole scrollback and screen to the passed filedescriptor.  The
3702  * invoking routine must close the fd.
3703  */
3704 #if 0
3705 /* EXTPROTO */
3706 void
3707 rxvt_scr_dump(rxvt_t* r, int fd)
3708 {
3709 	int			 row, wrote;
3710 	unsigned int	width, towrite;
3711 	char			r1[] = "\n";
3712 
3713 	for (row = SVLINES - PVTS(r, page)->nscrolled;
3714 	 row < SVLINES + r->TermWin.nrow - 1; row++) {
3715 	width = PSCR(r, page).tlen[row] >= 0 ? PSCR(r, page).tlen[row]
3716 					 : r->TermWin.ncol;
3717 	for (towrite = width; towrite; towrite -= wrote) {
3718 		wrote = write(fd, &(PSCR(r, page).text[row][width - towrite]),
3719 			  towrite);
3720 		if (wrote < 0)
3721 		return;		/* XXX: death, no report */
3722 	}
3723 	if (PSCR(r, page).tlen[row] >= 0)
3724 		if (write(fd, r1, 1) <= 0)
3725 		return;	/* XXX: death, no report */
3726 	}
3727 }
3728 #endif
3729 
3730 /* ------------------------------------------------------------------------- *
3731  *						   CHARACTER SELECTION							 *
3732  * ------------------------------------------------------------------------- */
3733 
3734 /*
3735  * -PVTS(r, page)->nscrolled <= (selection row) <= r->TermWin.nrow - 1
3736  */
3737 /* EXTPROTO */
3738 void
3739 rxvt_selection_check(rxvt_t* r, int page, int check_more)
3740 {
3741 	row_col_t	   pos;
3742 
3743 	if (!SEL(r).op ||
3744 		SEL(r).vt != page ||
3745 		SEL(r).screen != PVTS(r, page)->current_screen)
3746 		return;
3747 
3748 	pos.row = pos.col = 0;
3749 	if ((SEL(r).beg.row < -(RINT32T)PVTS(r, page)->nscrolled) ||
3750 		(SEL(r).beg.row >= r->TermWin.nrow) ||
3751 		(SEL(r).mark.row < -(RINT32T)PVTS(r, page)->nscrolled) ||
3752 		(SEL(r).mark.row >= r->TermWin.nrow) ||
3753 		(SEL(r).end.row < -(RINT32T)PVTS(r, page)->nscrolled) ||
3754 		(SEL(r).end.row >= r->TermWin.nrow) ||
3755 		( check_more == 1 &&
3756 		  PVTS(r, page)->current_screen == SEL(r).screen &&
3757 		  !RC_BEFORE(PSCR(r, page).cur, SEL(r).beg) &&
3758 		  RC_BEFORE(PSCR(r, page).cur, SEL(r).end)) ||
3759 		( check_more == 2 &&
3760 		  RC_BEFORE(SEL(r).beg, pos) &&
3761 		  RC_AFTER(SEL(r).end, pos)) ||
3762 		( check_more == 3 &&
3763 		  RC_AFTER(SEL(r).end, pos)) ||
3764 		( check_more == 4	/* screen width change */ &&
3765 		  ( SEL(r).beg.row != SEL(r).end.row ||
3766 		    SEL(r).end.col > r->TermWin.ncol)))
3767 		CLEAR_SELECTION(r);
3768 }
3769 
3770 /* ------------------------------------------------------------------------- */
3771 /*
3772  * Paste a selection direct to the command fd
3773  */
3774 /* INTPROTO */
3775 void
3776 rxvt_PasteIt(rxvt_t* r, int page, const unsigned char *data, unsigned int nitems)
3777 {
3778 	unsigned int	i, j, n;
3779 	unsigned char  *ds = rxvt_malloc(PROP_SIZE);
3780 
3781 	/*
3782 	** convert normal newline chars into common keyboard Return key
3783 	** sequence
3784 	*/
3785 	for (i = 0; i < nitems; i += PROP_SIZE) {
3786 		n = min(nitems - i, PROP_SIZE);
3787 		MEMCPY(ds, data + i, n);
3788 		for (j = 0; j < n; j++)
3789 			if (ds[j] == '\n')
3790 				ds[j] = '\r';
3791 		rxvt_tt_write(r, page, ds, (int)n);
3792 	}
3793 	free(ds);
3794 }
3795 
3796 
3797 /* ------------------------------------------------------------------------- */
3798 /*
3799  * Respond to a notification that a primary selection has been sent
3800  * EXT: SelectionNotify
3801  */
3802 /* EXTPROTO */
3803 int
3804 rxvt_selection_paste(rxvt_t* r, Window win, Atom prop, Bool delete_prop)
3805 {
3806 	long			nread = 0;
3807 	unsigned long	bytes_after;
3808 	XTextProperty	ct;
3809 #ifdef MULTICHAR_SET
3810 	int				dummy_count;
3811 	char**			cl;
3812 #endif
3813 
3814 	DBG_MSG(2,(stderr, "rxvt_selection_paste (%08lx, %lu, %d), wait=%2x\n", win, (unsigned long)prop, (int)delete_prop, r->h->selection_wait));
3815 
3816 	if (prop == None) {		/* check for failed XConvertSelection */
3817 #ifdef MULTICHAR_SET
3818 		if ((r->h->selection_type & Sel_CompoundText)) {
3819 			int		selnum = r->h->selection_type & Sel_whereMask;
3820 
3821 			r->h->selection_type = 0;
3822 			if (selnum != Sel_direct)
3823 				rxvt_selection_request_other(r, ATAB(r), XA_STRING, selnum);
3824 		}
3825 #endif
3826 		return 0;
3827 	}
3828 
3829 	for (;;) {
3830 		if (XGetWindowProperty(r->Xdisplay, win, prop, (long)(nread/4),
3831 			(long)(PROP_SIZE / 4), delete_prop, AnyPropertyType,
3832 			&ct.encoding, &ct.format, &ct.nitems, &bytes_after,
3833 			&ct.value) != Success)
3834 			break;
3835 		if (ct.encoding == None) {
3836 			DBG_MSG(2,(stderr, "rxvt_selection_paste: property didn't exist!\n"));
3837 			break;
3838 		}
3839 		if (ct.value == NULL) {
3840 			DBG_MSG(2,(stderr, "rxvt_selection_paste: property shooting blanks!\n"));
3841 			continue;
3842 		}
3843 		if (ct.nitems == 0) {
3844 			DBG_MSG(2,(stderr, "rxvt_selection_paste: property empty - also INCR end\n"));
3845 			if (r->h->selection_wait == Sel_normal && nread == 0) {
3846 				/*
3847 				** pass through again trying CUT_BUFFER0 if we've come
3848 				** from XConvertSelection() but nothing was presented
3849 				*/
3850 				DBG_MSG(2,(stderr, "rxvt_selection_request: pasting CUT_BUFFER0\n"));
3851 				rxvt_selection_paste(r, XROOT, XA_CUT_BUFFER0, False);
3852 			}
3853 			nread = -1;		/* discount any previous stuff */
3854 			break;
3855 		}
3856 
3857 		nread += ct.nitems;
3858 #ifdef MULTICHAR_SET
3859 		if (XmbTextPropertyToTextList(r->Xdisplay, &ct, &cl,
3860 			&dummy_count) == Success && cl) {
3861 			rxvt_PasteIt(r, ATAB(r), cl[0], STRLEN(cl[0]));
3862 			XFreeStringList(cl);
3863 		}
3864 		else
3865 #endif
3866 			rxvt_PasteIt(r, ATAB(r), ct.value, (unsigned int)ct.nitems);
3867 
3868 		if (bytes_after == 0)
3869 			break;
3870 		XFree(ct.value);
3871 	}
3872 
3873 	if (ct.value)
3874 		XFree(ct.value);
3875 	if (r->h->selection_wait == Sel_normal)
3876 		r->h->selection_wait = Sel_none;
3877 
3878 	DBG_MSG(2,(stderr, "rxvt_selection_paste: bytes written: %ld\n", nread));
3879 	return (int)nread;
3880 }
3881 
3882 
3883 /*
3884  * INCR support originally provided by Paul Sheer <psheer@obsidian.co.za>
3885  */
3886 /* EXTPROTO */
3887 void
3888 rxvt_selection_property(rxvt_t* r, Window win, Atom prop)
3889 {
3890 	int			 reget_time = 0;
3891 
3892 	if (prop == None)
3893 		return;
3894 
3895 	DBG_MSG(2,(stderr, "rxvt_selection_property(%08lx, %lu)\n", win, (unsigned long)prop));
3896 	if (r->h->selection_wait == Sel_normal) {
3897 		int			 a, afmt;
3898 		Atom			atype;
3899 		unsigned long   bytes_after, nitems;
3900 		unsigned char  *s = NULL;
3901 
3902 		a = XGetWindowProperty(r->Xdisplay, win, prop, 0L, 1L, False,
3903 				   r->h->xa[XA_INCR], &atype, &afmt, &nitems,
3904 				   &bytes_after, &s);
3905 		if (s)
3906 			XFree(s);
3907 		if (a != Success)
3908 			return;
3909 #ifndef OS_CYGWIN
3910 		if (atype == r->h->xa[XA_INCR]) {	/* start an INCR transfer */
3911 			DBG_MSG(2,(stderr, "rxvt_selection_property: INCR: starting transfer\n"));
3912 			XDeleteProperty(r->Xdisplay, win, prop);
3913 			XFlush(r->Xdisplay);
3914 			reget_time = 1;
3915 			r->h->selection_wait = Sel_incr;
3916 		}
3917 #endif
3918 	}
3919 	else if (r->h->selection_wait == Sel_incr) {
3920 		reget_time = 1;
3921 		if (rxvt_selection_paste(r, win, prop, True) == -1) {
3922 			DBG_MSG(2,(stderr, "rxvt_selection_property: INCR: clean end\n"));
3923 			r->h->selection_wait = Sel_none;
3924 			r->h->timeout[TIMEOUT_INCR].tv_sec = 0;	/* turn off timer */
3925 		}
3926 	}
3927 	if (reget_time) {	/* received more data so reget time */
3928 		(void)gettimeofday(&(r->h->timeout[TIMEOUT_INCR]), NULL);
3929 		/* ten seconds wait */
3930 		r->h->timeout[TIMEOUT_INCR].tv_sec += 10;
3931 	}
3932 }
3933 
3934 
3935 /* ------------------------------------------------------------------------- */
3936 /*
3937  * Request the current selection:
3938  * Order: > internal selection if available
3939  *		> PRIMARY, SECONDARY, CLIPBOARD if ownership is claimed (+)
3940  *		> CUT_BUFFER0
3941  * (+) if ownership is claimed but property is empty, rxvt_selection_paste()
3942  *	 will auto fallback to CUT_BUFFER0
3943  * EXT: button 2 release
3944  */
3945 /* EXTPROTO */
3946 void
3947 rxvt_selection_request(rxvt_t* r, int page, Time tm, int x, int y)
3948 {
3949 	DBG_MSG(2,(stderr, "rxvt_selection_request %d (%lu, %d, %d)\n", page, tm, x, y));
3950 	if (x < 0 || x >= VT_WIDTH(r) || y < 0 || y >= VT_HEIGHT(r))
3951 		return;			/* outside window */
3952 
3953 	if (SEL(r).text != NULL) {	/* internal selection */
3954 		DBG_MSG(2,(stderr, "rxvt_selection_request %d: pasting internal\n", page));
3955 		rxvt_PasteIt(r, page, SEL(r).text, SEL(r).len);
3956 		return;
3957 	}
3958 	else {
3959 		int			 i;
3960 
3961 		r->h->selection_request_time = tm;
3962 		r->h->selection_wait = Sel_normal;
3963 		for (i = Sel_Primary; i <= Sel_Clipboard; i++) {
3964 #ifdef MULTICHAR_SET
3965 			r->h->selection_type = Sel_CompoundText;
3966 #else
3967 			r->h->selection_type = 0;
3968 #endif
3969 			if (rxvt_selection_request_other(r, page,
3970 #ifdef MULTICHAR_SET
3971 				 r->h->xa[XA_COMPOUND_TEXT],
3972 #else
3973 				 XA_STRING,
3974 #endif
3975 				 i))
3976 			return;
3977 		}
3978 	}
3979 	r->h->selection_wait = Sel_none;	/* don't loop in rxvt_selection_paste() */
3980 	DBG_MSG(2,(stderr, "rxvt_selection_request %d: pasting CUT_BUFFER0\n", page));
3981 	rxvt_selection_paste(r, XROOT, XA_CUT_BUFFER0, False);
3982 }
3983 
3984 
3985 /* INTPROTO */
3986 int
3987 rxvt_selection_request_other(rxvt_t* r, int page, Atom target, int selnum)
3988 {
3989 	Atom			sel;
3990 #if DEBUG_LEVEL
3991 	char		   *debug_xa_names[] = { "PRIMARY", "SECONDARY", "CLIPBOARD" };
3992 #endif
3993 
3994 	r->h->selection_type |= selnum;
3995 	if (selnum == Sel_Primary)
3996 		sel = XA_PRIMARY;
3997 	else if (selnum == Sel_Secondary)
3998 		sel = XA_SECONDARY;
3999 	else
4000 		sel = r->h->xa[XA_CLIPBOARD];
4001 	if (XGetSelectionOwner(r->Xdisplay, sel) != None) {
4002 		DBG_MSG(2,(stderr, "rxvt_selection_request_other %d: pasting %s\n", page, debug_xa_names[selnum]));
4003 
4004 		XConvertSelection(r->Xdisplay, sel, target,
4005 			r->h->xa[XA_VT_SELECTION], PVTS(r, page)->vt,
4006 			r->h->selection_request_time);
4007 		return 1;
4008 	}
4009 	return 0;
4010 }
4011 
4012 
4013 /* ------------------------------------------------------------------------- */
4014 /*
4015  * Clear all selected text
4016  * EXT: SelectionClear
4017  */
4018 /* EXTPROTO */
4019 void
4020 rxvt_process_selectionclear(rxvt_t* r, int page)
4021 {
4022 	DBG_MSG(2,(stderr, "rxvt_process_selectionclear %d ()\n", page));
4023 
4024 	r->h->want_refresh = 1;
4025 	if (SEL(r).text)
4026 		free(SEL(r).text);
4027 	SEL(r).text = NULL;
4028 	SEL(r).len = 0;
4029 	CLEAR_SELECTION(r);
4030 	SEL(r).vt = -1;
4031 
4032 	SEL(r).op = SELECTION_CLEAR;
4033 	SEL(r).screen = PRIMARY;
4034 	SEL(r).clicks = 0;
4035 }
4036 
4037 
4038 /* ------------------------------------------------------------------------- */
4039 /*
4040  * Copy a selection into the cut buffer
4041  * EXT: button 1 or 3 release
4042  */
4043 /* EXTPROTO */
4044 void
4045 rxvt_selection_make(rxvt_t* r, int page, Time tm)
4046 {
4047 	int				i, col, end_col, row, end_row;
4048 	unsigned char*	new_selection_text;
4049 	unsigned char*	str;
4050 	text_t*			t;
4051 #ifdef MULTICHAR_SET
4052 	rend_t*			tr;
4053 #endif
4054 #ifdef ACS_ASCII
4055 	rend_t*			re;
4056 #endif
4057 
4058 	DBG_MSG(2,(stderr, "rxvt_selection_make %d (): sel.op=%d, sel.clicks=%d\n", page, SEL(r).op, SEL(r).clicks));
4059 	switch (SEL(r).op) {
4060 	case SELECTION_CONT:
4061 		break;
4062 	case SELECTION_INIT:
4063 		CLEAR_SELECTION(r);
4064 		/* FALLTHROUGH */
4065 	case SELECTION_BEGIN:
4066 		SEL(r).op = SELECTION_DONE;
4067 		/* FALLTHROUGH */
4068 	default:
4069 		return;
4070 	}
4071 	SEL(r).op = SELECTION_DONE;
4072 	SEL(r).vt = page;	/* update selection vt */
4073 
4074 	if (SEL(r).clicks == 4)
4075 		return;			/* nothing selected, go away */
4076 
4077 	assert ((SEL(r).end.row - SEL(r).beg.row + 1) > 0);
4078 	assert ((r->TermWin.ncol + 1) > 0);
4079 	i = (SEL(r).end.row - SEL(r).beg.row + 1)
4080 		* (r->TermWin.ncol + 1) + 1;
4081 	/* possible integer overflow? */
4082 	assert (i > 0);
4083 	str = rxvt_malloc(i * sizeof(char));
4084 
4085 	new_selection_text = (unsigned char *)str;
4086 
4087 	col = SEL(r).beg.col;
4088 	MAX_IT(col, 0);
4089 	row = SEL(r).beg.row + SVLINES;
4090 	end_row = SEL(r).end.row + SVLINES;
4091 
4092 	/*
4093 	** A: rows before end row
4094 	*/
4095 	for (; row < end_row; row++, col = 0) {
4096 		t = &(PSCR(r, page).text[row][col]);
4097 #ifdef MULTICHAR_SET
4098 		tr = &(PSCR(r, page).rend[row][col]);
4099 #endif	/* MULTICHAR_SET */
4100 #ifdef ACS_ASCII
4101 		re = &(PSCR(r, page).rend[row][col]);
4102 #endif
4103 		if ((end_col = PSCR(r, page).tlen[row]) == -1)
4104 			end_col = r->TermWin.ncol;
4105 
4106 
4107 		/*
4108 		** Looks like a completely mess. Think about the logic here
4109 		** carefully. ;-)
4110 		** Patch source:
4111 		** http://gentoo.nedlinux.nl/distfiles/rxvt-2.7.10-rk.patch
4112 		*/
4113 		for (; col < end_col; col++, str++, t++)	{
4114 #ifdef MULTICHAR_SET
4115 			if ((ENC_EUCJ == r->encoding_method) &&
4116 				(*t & 0x80) &&
4117 				!(*tr & RS_multiMask))	{
4118 				*str++ = 0x8E;
4119 				tr ++;
4120 			}
4121 #endif	/* MULTICHAR_SET */
4122 #ifdef ACS_ASCII
4123 			if ((*re++ & RS_acsFont) && *t >= 0x60 && *t < 0x80)
4124 				*str = r->h->rs[Rs_acs_chars][(*t) - 0x60];
4125 			else
4126 #endif	/* ACS_ASCII */
4127 			*str = *t;
4128 		}
4129 
4130 
4131 		if (PSCR(r, page).tlen[row] != -1)	{
4132 #ifdef DONT_SELECT_TRAILING_SPACES
4133 			STRIP_TRAILING_SPACE(str, new_selection_text);
4134 #endif
4135 			*str++ = '\n';
4136 		}
4137 	}
4138 
4139 	/*
4140 	** B: end row
4141 	*/
4142 	t = &(PSCR(r, page).text[row][col]);
4143 #ifdef MULTICHAR_SET
4144 	tr = &(PSCR(r, page).rend[row][col]);
4145 #endif	/* MULTICHAR_SET */
4146 #ifdef ACS_ASCII
4147 	re = &(PSCR(r, page).rend[row][col]);
4148 #endif
4149 	end_col = PSCR(r, page).tlen[row];
4150 	if (end_col == -1 || SEL(r).end.col <= end_col)
4151 		end_col = SEL(r).end.col;
4152 	MIN_IT(end_col, r->TermWin.ncol);	/* CHANGE */
4153 
4154 
4155 	/*
4156 	** Looks like a completely mess. Think about the logic here
4157 	** carefully. ;-)
4158 	** Patch source:
4159 	** http://gentoo.nedlinux.nl/distfiles/rxvt-2.7.10-rk.patch
4160 	*/
4161 	for (; col < end_col; col++, str++, t++)	{
4162 #ifdef MULTICHAR_SET
4163 		if ((ENC_EUCJ == r->encoding_method) &&
4164 			(*t & 0x80) &&
4165 			!(*tr & RS_multiMask))	{
4166 			*str++ = 0x8E;
4167 			tr ++;
4168 		}
4169 #endif	/* MULTICHAR_SET */
4170 #ifdef ACS_ASCII
4171 		if ((*re++ & RS_acsFont) && *t >= 0x60 && *t < 0x80)
4172 			*str = r->h->rs[Rs_acs_chars][(*t) - 0x60];
4173 		else
4174 #endif	/* ACS_ASCII */
4175 		*str = *t;
4176 	}
4177 
4178 #ifdef DONT_SELECT_TRAILING_SPACES
4179 	STRIP_TRAILING_SPACE(str, new_selection_text);
4180 #endif
4181 
4182 
4183 #ifndef NO_OLD_SELECTION
4184 	if (r->selection_style == OLD_SELECT)
4185 		if (end_col == r->TermWin.ncol)	{
4186 			*str++ = '\n';
4187 		}
4188 #endif
4189 #ifndef NO_NEW_SELECTION
4190 	if (r->selection_style != OLD_SELECT)
4191 		if (end_col != SEL(r).end.col)	{
4192 			*str++ = '\n';
4193 		}
4194 #endif
4195 	*str = '\0';
4196 	if ((i = STRLEN((char *)new_selection_text)) == 0) {
4197 		free(new_selection_text);
4198 		return;
4199 	}
4200 	SEL(r).len = i;
4201 	if (SEL(r).text)
4202 		free(SEL(r).text);
4203 	SEL(r).text = new_selection_text;
4204 
4205 	XSetSelectionOwner(r->Xdisplay, XA_PRIMARY, PVTS(r, page)->vt, tm);
4206 	if (XGetSelectionOwner(r->Xdisplay, XA_PRIMARY) != PVTS(r, page)->vt)
4207 		rxvt_print_error("can't get primary selection");
4208 	XChangeProperty(r->Xdisplay, XROOT, XA_CUT_BUFFER0, XA_STRING, 8,
4209 		PropModeReplace, SEL(r).text, (int)SEL(r).len);
4210 	r->h->selection_time = tm;
4211 	DBG_MSG(2,(stderr, "rxvt_selection_make %d (): sel.len=%d\n", page, SEL(r).len));
4212 	DBG_MSG(1,(stderr, "sel.text=%s\n", SEL(r).text));
4213 }
4214 
4215 
4216 /* ------------------------------------------------------------------------- */
4217 /*
4218  * Mark or select text based upon number of clicks: 1, 2, or 3
4219  * EXT: button 1 press
4220  */
4221 /* EXTPROTO */
4222 void
4223 rxvt_selection_click(rxvt_t* r, int page, int clicks, int x, int y)
4224 {
4225 	DBG_MSG(2,(stderr, "rxvt_selection_click %d (%d, %d, %d)\n", page, clicks, x, y));
4226 
4227 	SEL(r).vt = page;
4228 	clicks = ((clicks - 1) % 3) + 1;
4229 	SEL(r).clicks = clicks;	/* save clicks so extend will work */
4230 
4231 #ifdef THAI
4232 	if (r->Options & Opt_thai)
4233 		rxvt_selection_start_colrow(r, page, ThaiPixel2Col(r, page, x,y), Pixel2Row(y));
4234 	else
4235 #endif	/* THAI */
4236 	rxvt_selection_start_colrow(r, page, Pixel2Col(x), Pixel2Row(y));
4237 
4238 	if (clicks == 2 || clicks == 3)
4239 		rxvt_selection_extend_colrow(r, page, SEL(r).mark.col,
4240 			SEL(r).mark.row + VSTART,
4241 			0,	/* button 3	 */
4242 			1,	/* button press */
4243 			0);	/* click change */
4244 }
4245 
4246 
4247 /* ------------------------------------------------------------------------- */
4248 /*
4249  * Mark a selection at the specified col/row
4250  */
4251 /* INTPROTO */
4252 void
4253 rxvt_selection_start_colrow(rxvt_t* r, int page, int col, int row)
4254 {
4255 	r->h->want_refresh = 1;
4256 	SEL(r).mark.col = col;
4257 	SEL(r).mark.row = row - VSTART;
4258 	MAX_IT(SEL(r).mark.row, -(RINT32T)PVTS(r, page)->nscrolled);
4259 	MIN_IT(SEL(r).mark.row, (RINT32T)r->TermWin.nrow - 1);
4260 	MAX_IT(SEL(r).mark.col, 0);
4261 	MIN_IT(SEL(r).mark.col, (RINT32T)r->TermWin.ncol - 1);
4262 
4263 	if (SEL(r).op) {
4264 		/* clear the old selection */
4265 		SEL(r).beg.row = SEL(r).end.row = SEL(r).mark.row;
4266 		SEL(r).beg.col = SEL(r).end.col = SEL(r).mark.col;
4267 	}
4268 	SEL(r).op = SELECTION_INIT;
4269 	SEL(r).screen = PVTS(r, page)->current_screen;
4270 	r->selection.vt = page;
4271 }
4272 
4273 
4274 /* ------------------------------------------------------------------------- */
4275 /*
4276  * Word select: select text for 2 clicks
4277  * We now only find out the boundary in one direction
4278  */
4279 
4280 /* what do we want: spaces/tabs are delimiters or cutchars or non-cutchars */
4281 #define DELIMIT_TEXT(x) \
4282 	(((x) == ' ' || (x) == '\t') ? 2 : (STRCHR(r->h->rs[Rs_cutchars], (x)) != NULL))
4283 #ifdef MULTICHAR_SET
4284 # define DELIMIT_REND(x)	(((x) & RS_multiMask) ? 1 : 0)
4285 #else
4286 # define DELIMIT_REND(x)	1
4287 #endif
4288 
4289 /* INTPROTO */
4290 void
4291 rxvt_selection_delimit_word(rxvt_t* r, int page, enum page_dirn dirn, const row_col_t *mark, row_col_t *ret)
4292 {
4293 	int			 col, row, dirnadd, tcol, trow, w1, w2;
4294 	row_col_t	   bound;
4295 	text_t		 *stp;
4296 	rend_t		 *srp;
4297 
4298 
4299 	r->selection.vt = page;	/* update selection vt */
4300 
4301 	if (dirn == UP) {
4302 		bound.row = SVLINES - PVTS(r, page)->nscrolled - 1;
4303 		bound.col = 0;
4304 		dirnadd = -1;
4305 	}
4306 	else {
4307 		bound.row = SVLINES + r->TermWin.nrow;
4308 		bound.col = r->TermWin.ncol - 1;
4309 		dirnadd = 1;
4310 	}
4311 	row = mark->row + SVLINES;
4312 	col = mark->col;
4313 	MAX_IT(col, 0);
4314 /* find the edge of a word */
4315 	stp = &(PSCR(r, page).text[row][col]);
4316 	w1 = DELIMIT_TEXT(*stp);
4317 
4318 	if (r->selection_style != NEW_SELECT) {
4319 		if (w1 == 1) {
4320 			stp += dirnadd;
4321 			if (DELIMIT_TEXT(*stp) == 1)
4322 				goto Old_Word_Selection_You_Die;
4323 			col += dirnadd;
4324 		}
4325 		w1 = 0;
4326 	}
4327 	srp = (&PSCR(r, page).rend[row][col]);
4328 	w2 = DELIMIT_REND(*srp);
4329 
4330 	for (;;) {
4331 		for (; col != bound.col; col += dirnadd) {
4332 			stp += dirnadd;
4333 			if (DELIMIT_TEXT(*stp) != w1)
4334 				break;
4335 			srp += dirnadd;
4336 			if (DELIMIT_REND(*srp) != w2)
4337 				break;
4338 		}
4339 		if ((col == bound.col) && (row != bound.row)) {
4340 			if (PSCR(r, page).tlen[(row - (dirn == UP ? 1 : 0))] == -1) {
4341 				trow = row + dirnadd;
4342 				tcol = dirn == UP ? r->TermWin.ncol - 1 : 0;
4343 				if (PSCR(r, page).text[trow] == NULL)
4344 					break;
4345 				stp = &(PSCR(r, page).text[trow][tcol]);
4346 				srp = &(PSCR(r, page).rend[trow][tcol]);
4347 				if (DELIMIT_TEXT(*stp) != w1 ||
4348 					DELIMIT_REND(*srp) != w2)
4349 					break;
4350 				row = trow;
4351 				col = tcol;
4352 				continue;
4353 			}
4354 		}
4355 		break;
4356 	}
4357 
4358 Old_Word_Selection_You_Die:
4359 	DBG_MSG(2,(stderr, "rxvt_selection_delimit_word %d (%s,...) @ (r:%3d, c:%3d) has boundary (r:%3d, c:%3d)\n", page, (dirn == UP ? "up	" : "down"), mark->row, mark->col, row - SVLINES, col));
4360 
4361 	if (dirn == DN)
4362 		col++;			/* put us on one past the end */
4363 
4364 /* Poke the values back in */
4365 	ret->row = row - SVLINES;
4366 	ret->col = col;
4367 }
4368 
4369 
4370 /* ------------------------------------------------------------------------- */
4371 /*
4372  * Extend the selection to the specified x/y pixel location
4373  * EXT: button 3 press; button 1 or 3 drag
4374  * flag == 0 ==> button 1
4375  * flag == 1 ==> button 3 press
4376  * flag == 2 ==> button 3 motion
4377  */
4378 /* EXTPROTO */
4379 void
4380 rxvt_selection_extend(rxvt_t* r, int page, int x, int y, int flag)
4381 {
4382 	int			 col, row;
4383 
4384 #ifdef THAI
4385 	if (r->Options & Opt_thai)
4386 		col = ThaiPixel2Col(r, page, x, y);
4387 	else
4388 #endif	/* THAI */
4389 	col = Pixel2Col(x);
4390 	row = Pixel2Row(y);
4391 	MAX_IT(row, 0);
4392 	MIN_IT(row, (int)r->TermWin.nrow - 1);
4393 	MAX_IT(col, 0);
4394 	MIN_IT(col, (int)r->TermWin.ncol);
4395 
4396 #ifndef NO_NEW_SELECTION
4397 /*
4398  * If we're selecting characters (single click) then we must check first
4399  * if we are at the same place as the original mark.  If we are then
4400  * select nothing.  Otherwise, if we're to the right of the mark, you have to
4401  * be _past_ a character for it to be selected.
4402  */
4403 	if (r->selection_style != OLD_SELECT) {
4404 		if (((SEL(r).clicks % 3) == 1) &&
4405 			!flag &&
4406 			(col == SEL(r).mark.col && (row == SEL(r).mark.row + VSTART))) {
4407 			/* select nothing */
4408 			SEL(r).beg.row = SEL(r).end.row = 0;
4409 			SEL(r).beg.col = SEL(r).end.col = 0;
4410 			SEL(r).clicks = 4;
4411 			r->h->want_refresh = 1;
4412 			DBG_MSG(2,(stderr, "rxvt_selection_extend %d () sel.clicks = 4\n", page));
4413 			return;
4414 		}
4415 	}
4416 #endif
4417 	if (SEL(r).clicks == 4)
4418 		SEL(r).clicks = 1;
4419 	rxvt_selection_extend_colrow(r, page, col, row, !!flag,
4420 		/* ? button 3	  */
4421 		 flag == 1 ? 1 : 0,	/* ? button press  */
4422 		 0);	/* no click change */
4423 }
4424 
4425 
4426 #ifdef MULTICHAR_SET
4427 /* INTPROTO */
4428 void
4429 rxvt_selection_adjust_kanji(rxvt_t* r, int page)
4430 {
4431 	int			 c1, r1;
4432 
4433 	if (SEL(r).beg.col > 0) {
4434 		r1 = SEL(r).beg.row + SVLINES;
4435 		c1 = SEL(r).beg.col;
4436 		if (IS_MULTI2(PSCR(r, page).rend[r1][c1]) &&
4437 			IS_MULTI1(PSCR(r, page).rend[r1][c1 - 1]))
4438 			SEL(r).beg.col--;
4439 	}
4440 	if (SEL(r).end.col < r->TermWin.ncol) {
4441 		r1 = SEL(r).end.row + SVLINES;
4442 		c1 = SEL(r).end.col;
4443 		if (IS_MULTI1(PSCR(r, page).rend[r1][c1 - 1]) &&
4444 			IS_MULTI2(PSCR(r, page).rend[r1][c1]))
4445 			SEL(r).end.col++;
4446 	}
4447 }
4448 #endif				/* MULTICHAR_SET */
4449 
4450 
4451 /* ------------------------------------------------------------------------- */
4452 /*
4453  * Extend the selection to the specified col/row
4454  */
4455 /* INTPROTO */
4456 void
4457 rxvt_selection_extend_colrow(rxvt_t* r, int page, RINT32T col, RINT32T row, int button3, int buttonpress, int clickchange)
4458 {
4459 	unsigned int	ncol = r->TermWin.ncol;
4460 	row_col_t		pos;
4461 #ifndef NO_NEW_SELECTION
4462 	int			 end_col;
4463 	enum {
4464 		LEFT, RIGHT
4465 	} closeto = RIGHT;
4466 #endif
4467 
4468 
4469 	DBG_MSG(2,(stderr, "rxvt_selection_extend_colrow %d (c:%d, r:%d, %d, %d) clicks:%d, op:%d\n", page, col, row, button3, buttonpress, SEL(r).clicks, SEL(r).op));
4470 	DBG_MSG(2,(stderr, "rxvt_selection_extend_colrow %d () ENT  b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)\n", page, SEL(r).beg.row, SEL(r).beg.col, SEL(r).mark.row, SEL(r).mark.col, SEL(r).end.row, SEL(r).end.col));
4471 
4472 	r->h->want_refresh = 1;
4473 	switch (SEL(r).op) {
4474 	case SELECTION_INIT:
4475 		CLEAR_SELECTION(r);
4476 		SEL(r).op = SELECTION_BEGIN;
4477 		/* FALLTHROUGH */
4478 	case SELECTION_BEGIN:
4479 		if (row != SEL(r).mark.row ||
4480 			col != SEL(r).mark.col ||
4481 			(!button3 && buttonpress))
4482 			SEL(r).op = SELECTION_CONT;
4483 		break;
4484 	case SELECTION_DONE:
4485 		SEL(r).op = SELECTION_CONT;
4486 		/* FALLTHROUGH */
4487 	case SELECTION_CONT:
4488 		break;
4489 	case SELECTION_CLEAR:
4490 		rxvt_selection_start_colrow(r, page, col, row);
4491 		/* FALLTHROUGH */
4492 	default:
4493 		return;
4494 	}
4495 
4496 	if (SEL(r).beg.col == SEL(r).end.col &&
4497 		SEL(r).beg.col != SEL(r).mark.col &&
4498 		SEL(r).beg.row == SEL(r).end.row &&
4499 		SEL(r).beg.row != SEL(r).mark.row) {
4500 		SEL(r).beg.col = SEL(r).end.col = SEL(r).mark.col;
4501 		SEL(r).beg.row = SEL(r).end.row = SEL(r).mark.row;
4502 		DBG_MSG(2,(stderr, "rxvt_selection_extend_colrow %d () ENT2 b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)\n", page, SEL(r).beg.row, SEL(r).beg.col, SEL(r).mark.row, SEL(r).mark.col, SEL(r).end.row, SEL(r).end.col));
4503 	}
4504 
4505 	pos.col = col;
4506 	pos.row = row;
4507 
4508 	pos.row -= VSTART;	/* adjust for scroll */
4509 
4510 
4511 #ifndef NO_OLD_SELECTION
4512 	/*
4513 	** This mimics some of the selection behaviour of version 2.20
4514 	** and before.
4515 	** There are no ``selection modes'', button3 is always character
4516 	** extension.
4517 	** Note: button3 drag is always available, c.f. v2.20
4518 	** Selection always terminates (left or right as appropriate) at
4519 	** the mark.
4520 	*/
4521 	if (r->selection_style == OLD_SELECT) {
4522 		if (SEL(r).clicks == 1 || button3) {
4523 			if (r->h->hate_those_clicks) {
4524 				r->h->hate_those_clicks = 0;
4525 				if (SEL(r).clicks == 1) {
4526 					SEL(r).beg.row = SEL(r).mark.row;
4527 					SEL(r).beg.col = SEL(r).mark.col;
4528 				}
4529 				else {
4530 					SEL(r).mark.row = SEL(r).beg.row;
4531 					SEL(r).mark.col = SEL(r).beg.col;
4532 				}
4533 			}
4534 
4535 			if (RC_BEFORE(pos, SEL(r).mark)) {
4536 				SEL(r).end.row = SEL(r).mark.row;
4537 				SEL(r).end.col = SEL(r).mark.col + 1;
4538 				SEL(r).beg.row = pos.row;
4539 				SEL(r).beg.col = pos.col;
4540 			}
4541 			else {
4542 				SEL(r).beg.row = SEL(r).mark.row;
4543 				SEL(r).beg.col = SEL(r).mark.col;
4544 				SEL(r).end.row = pos.row;
4545 				SEL(r).end.col = pos.col + 1;
4546 			}
4547 # ifdef MULTICHAR_SET
4548 			rxvt_selection_adjust_kanji(r, page);
4549 # endif				/* MULTICHAR_SET */
4550 		}
4551 		else if (SEL(r).clicks == 2) {
4552 			rxvt_selection_delimit_word(r, page, UP, &(SEL(r).mark),
4553 				&(SEL(r).beg));
4554 			rxvt_selection_delimit_word(r, page, DN, &(SEL(r).mark),
4555 				&(SEL(r).end));
4556 			r->h->hate_those_clicks = 1;
4557 		}
4558 		else if (SEL(r).clicks == 3) {
4559 			SEL(r).beg.row = SEL(r).end.row = SEL(r).mark.row;
4560 			SEL(r).beg.col = 0;
4561 			SEL(r).end.col = ncol;
4562 			r->h->hate_those_clicks = 1;
4563 		}
4564 
4565 		DBG_MSG(2,(stderr, "rxvt_selection_extend_colrow %d () EXIT b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)\n", page, SEL(r).beg.row, SEL(r).beg.col, SEL(r).mark.row, SEL(r).mark.col, SEL(r).end.row, SEL(r).end.col));
4566 		return;
4567 	}
4568 #endif				/* ! NO_OLD_SELECTION */
4569 
4570 
4571 #ifndef NO_NEW_SELECTION
4572 	/* selection_style must not be OLD_SELECT to get here */
4573 	/*
4574 	** This is mainly xterm style selection with a couple of
4575 	** differences, mainly in the way button3 drag extension
4576 	** works.
4577 	** We're either doing: button1 drag; button3 press; or
4578 	** button3 drag
4579 	**  a) button1 drag : select around a midpoint/word/line -
4580 	** that point/word/line is always at the left/right edge
4581 	** of the SEL(r).
4582 	**  b) button3 press: extend/contract character/word/line
4583 	** at whichever edge of the selection we are closest to.
4584 	**  c) button3 drag : extend/contract character/word/line
4585 	** - we select around a point/word/line which is either
4586 	** the start or end of the selection and it was decided
4587 	** by whichever point/word/line was `fixed' at the time
4588 	** of the most recent button3 press
4589 	*/
4590 	if (button3 && buttonpress) {	/* button3 press */
4591 		/* first determine which edge of the selection we are
4592 		** closest to
4593 		*/
4594 		if (RC_BEFORE(pos, SEL(r).beg) ||
4595 			(!RC_AFTER(pos, SEL(r).end) &&
4596 			 (((pos.col - SEL(r).beg.col) +
4597 			   ((pos.row - SEL(r).beg.row) * ncol)) <
4598 			  ((SEL(r).end.col - pos.col) +
4599 			   ((SEL(r).end.row - pos.row) * ncol)))))
4600 			 closeto = LEFT;
4601 
4602 		if (closeto == LEFT) {
4603 			SEL(r).beg.row = pos.row;
4604 			SEL(r).beg.col = pos.col;
4605 			SEL(r).mark.row = SEL(r).end.row;
4606 			SEL(r).mark.col = SEL(r).end.col
4607 					- (SEL(r).clicks == 2);
4608 		}
4609 		else {
4610 			SEL(r).end.row = pos.row;
4611 			SEL(r).end.col = pos.col;
4612 			SEL(r).mark.row = SEL(r).beg.row;
4613 			SEL(r).mark.col = SEL(r).beg.col;
4614 		}
4615 	}
4616 	else {	/* button1 drag or button3 drag */
4617 		if (RC_AFTER(SEL(r).mark, pos)) {
4618 			if ((SEL(r).mark.row == SEL(r).end.row) &&
4619 				(SEL(r).mark.col == SEL(r).end.col) &&
4620 				clickchange && SEL(r).clicks == 2)
4621 				SEL(r).mark.col--;
4622 			SEL(r).beg.row = pos.row;
4623 			SEL(r).beg.col = pos.col;
4624 			SEL(r).end.row = SEL(r).mark.row;
4625 			SEL(r).end.col = SEL(r).mark.col
4626 			   + (SEL(r).clicks == 2);
4627 		}
4628 		else {
4629 		SEL(r).beg.row = SEL(r).mark.row;
4630 			SEL(r).beg.col = SEL(r).mark.col;
4631 			SEL(r).end.row = pos.row;
4632 			SEL(r).end.col = pos.col;
4633 		}
4634 	}
4635 
4636 
4637 	if (SEL(r).clicks == 1) {
4638 		end_col = PSCR(r, page).tlen[SEL(r).beg.row +
4639 					SVLINES];
4640 		if (end_col != -1 && SEL(r).beg.col > end_col) {
4641 #if 1
4642 			SEL(r).beg.col = ncol;
4643 #else
4644 			if (SEL(r).beg.row != SEL(r).end.row)
4645 				SEL(r).beg.col = ncol;
4646 			else
4647 				SEL(r).beg.col = SEL(r).mark.col;
4648 #endif
4649 		}
4650 		end_col = PSCR(r, page).tlen[SEL(r).end.row +
4651 					SVLINES];
4652 		if (end_col != -1 && SEL(r).end.col > end_col)
4653 			SEL(r).end.col = ncol;
4654 
4655 # ifdef MULTICHAR_SET
4656 		rxvt_selection_adjust_kanji(r, page);
4657 # endif				/* MULTICHAR_SET */
4658 	}
4659 	else if (SEL(r).clicks == 2) {
4660 		if (RC_AFTER(SEL(r).end, SEL(r).beg))
4661 			SEL(r).end.col--;
4662 		rxvt_selection_delimit_word(r, page, UP, &(SEL(r).beg),
4663 			&(SEL(r).beg));
4664 		rxvt_selection_delimit_word(r, page, DN, &(SEL(r).end),
4665 			&(SEL(r).end));
4666 	}
4667 	else if (SEL(r).clicks == 3) {
4668 #ifndef NO_FRILLS
4669 		if ((r->Options & Opt_tripleclickwords)) {
4670 			int			 end_row;
4671 
4672 			rxvt_selection_delimit_word(r, page, UP, &(SEL(r).beg),
4673 				&(SEL(r).beg));
4674 			end_row = PSCR(r, page).tlen[SEL(r).mark.row +
4675 						SVLINES];
4676 			for (end_row = SEL(r).mark.row;
4677 				end_row < r->TermWin.nrow; end_row++) {
4678 				end_col = PSCR(r, page).tlen[end_row +
4679 							SVLINES];
4680 				if (end_col != -1) {
4681 					SEL(r).end.row = end_row;
4682 					SEL(r).end.col = end_col;
4683 					rxvt_selection_trim(r, page);
4684 					break;
4685 				}
4686 			}	/* for */
4687 		}
4688 		else
4689 #endif
4690 		{
4691 			if (RC_AFTER(SEL(r).mark, SEL(r).beg))
4692 				SEL(r).mark.col++;
4693 			SEL(r).beg.col = 0;
4694 			SEL(r).end.col = ncol;
4695 		}
4696 	}	/* if ((r->Options & Opt_tripleclickwords)) */
4697 
4698 	if (button3 && buttonpress) {
4699 		/* mark may need to be changed */
4700 		if (closeto == LEFT) {
4701 			SEL(r).mark.row = SEL(r).end.row;
4702 			SEL(r).mark.col = SEL(r).end.col - (SEL(r).clicks == 2);
4703 		}
4704 		else {
4705 			SEL(r).mark.row = SEL(r).beg.row;
4706 			SEL(r).mark.col = SEL(r).beg.col;
4707 		}
4708 	}
4709 
4710 	DBG_MSG(2,(stderr, "rxvt_selection_extend_colrow %d () EXIT b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)\n", page, SEL(r).beg.row, SEL(r).beg.col, SEL(r).mark.row, SEL(r).mark.col, SEL(r).end.row, SEL(r).end.col));
4711 
4712 #endif				/* ! NO_NEW_SELECTION */
4713 }
4714 
4715 
4716 #ifndef NO_FRILLS
4717 /* INTPROTO */
4718 void
4719 rxvt_selection_trim(rxvt_t* r, int page)
4720 {
4721 	RINT32T		 end_col, end_row;
4722 	text_t		 *stp;
4723 
4724 	end_col = SEL(r).end.col;
4725 	end_row = SEL(r).end.row;
4726 	for ( ; end_row >= SEL(r).beg.row; ) {
4727 		stp = PSCR(r, page).text[end_row + SVLINES];
4728 		while (--end_col >= 0) {
4729 			if (stp[end_col] != ' ' && stp[end_col] != '\t')
4730 				break;
4731 		}
4732 		if (end_col >= 0 ||
4733 			PSCR(r, page).tlen[end_row - 1 + SVLINES] != -1) {
4734 			SEL(r).end.col = end_col + 1;
4735 			SEL(r).end.row = end_row;
4736 			break;
4737 		}
4738 		end_row--;
4739 		end_col = r->TermWin.ncol;
4740 	}
4741 
4742 	if (SEL(r).mark.row > SEL(r).end.row) {
4743 		SEL(r).mark.row = SEL(r).end.row;
4744 		SEL(r).mark.col = SEL(r).end.col;
4745 	}
4746 	else if (SEL(r).mark.row == SEL(r).end.row &&
4747 		SEL(r).mark.col > SEL(r).end.col)
4748 		SEL(r).mark.col = SEL(r).end.col;
4749 }
4750 #endif
4751 
4752 
4753 /* ------------------------------------------------------------------------- */
4754 /*
4755  * Double click on button 3 when already selected
4756  * EXT: button 3 double click
4757  */
4758 /* EXTPROTO */
4759 void
4760 rxvt_selection_rotate(rxvt_t* r, int page, int x, int y)
4761 {
4762 	SEL(r).clicks = SEL(r).clicks % 3 + 1;
4763 
4764 #ifdef THAI
4765 	if (r->Options & Opt_thai)
4766 		rxvt_selection_extend_colrow(r, page,
4767 			ThaiPixel2Col (r, page, x, y), Pixel2Row (y), 1, 0, 1);
4768 	else
4769 #endif	/* THAI */
4770 	rxvt_selection_extend_colrow (r, page, Pixel2Col(x),
4771 		Pixel2Row(y), 1, 0, 1);
4772 }
4773 
4774 
4775 
4776 /* ------------------------------------------------------------------------- */
4777 /*
4778  * Respond to a request for our current selection
4779  * EXT: SelectionRequest
4780  */
4781 /* EXTPROTO */
4782 void
4783 rxvt_process_selectionrequest (rxvt_t* r, int page, const XSelectionRequestEvent *rq)
4784 {
4785 	XSelectionEvent ev;
4786 #ifdef USE_XIM
4787 	Atom		  target_list[4];
4788 #else
4789 	Atom		  target_list[3];
4790 #endif
4791 	Atom			target;
4792 	XTextProperty   ct;
4793 	XICCEncodingStyle style;
4794 	char		   *cl[2], dummy[1];
4795 
4796 	ev.type = SelectionNotify;
4797 	ev.property = None;
4798 	ev.display = rq->display;
4799 	ev.requestor = rq->requestor;
4800 	ev.selection = rq->selection;
4801 	ev.target = rq->target;
4802 	ev.time = rq->time;
4803 
4804 	if (rq->target == r->h->xa[XA_TARGETS]) {
4805 		target_list[0] = r->h->xa[XA_TARGETS];
4806 		target_list[1] = XA_STRING;
4807 		target_list[2] = r->h->xa[XA_TEXT];
4808 #ifdef USE_XIM
4809 		target_list[3] = r->h->xa[XA_COMPOUND_TEXT];
4810 #endif
4811 		XChangeProperty(r->Xdisplay, rq->requestor, rq->property,
4812 			XA_ATOM, 32, PropModeReplace,
4813 			(unsigned char *)target_list,
4814 			(sizeof(target_list) / sizeof(target_list[0])));
4815 		ev.property = rq->property;
4816 	}
4817 	else if (rq->target == r->h->xa[XA_MULTIPLE]) {
4818 		/* TODO: Handle MULTIPLE */
4819 	}
4820 	else if (rq->target == r->h->xa[XA_TIMESTAMP] && SEL(r).text) {
4821 		XChangeProperty(r->Xdisplay, rq->requestor, rq->property,
4822 			XA_INTEGER,
4823 			sizeof(Time) > 4 ? 32 : (8 * sizeof(Time)),
4824 			PropModeReplace, (unsigned char*)&r->h->selection_time,
4825 			sizeof(Time) > 4 ? sizeof(Time)/4 : 1);
4826 		ev.property = rq->property;
4827 	}
4828 	else if (rq->target == XA_STRING ||
4829 		rq->target == r->h->xa[XA_COMPOUND_TEXT] ||
4830 		rq->target == r->h->xa[XA_TEXT]) {
4831 #ifdef USE_XIM
4832 		short		   freect = 0;
4833 #endif
4834 		int			 selectlen;
4835 
4836 #ifdef USE_XIM
4837 		if (rq->target != XA_STRING) {
4838 			target = r->h->xa[XA_COMPOUND_TEXT];
4839 			style = (rq->target == r->h->xa[XA_COMPOUND_TEXT])
4840 				? XCompoundTextStyle : XStdICCTextStyle;
4841 		} else
4842 #endif
4843 		{
4844 			target = XA_STRING;
4845 			style = XStringStyle;
4846 		}
4847 		if (SEL(r).text) {
4848 			cl[0] = (char *)SEL(r).text;
4849 			selectlen = SEL(r).len;
4850 		}
4851 		else {
4852 			cl[0] = dummy;
4853 			*dummy = '\0';
4854 			selectlen = 0;
4855 		}
4856 #ifdef USE_XIM
4857 		if (XmbTextListToTextProperty(r->Xdisplay, cl, 1, style, &ct) == Success)		/* if we failed to convert then send it raw */
4858 			freect = 1;
4859 		else
4860 #endif
4861 		{
4862 			ct.value = (unsigned char *)cl[0];
4863 			ct.nitems = selectlen;
4864 		}
4865 		XChangeProperty(r->Xdisplay, rq->requestor, rq->property,
4866 			target, 8, PropModeReplace,
4867 			ct.value, (int)ct.nitems);
4868 		ev.property = rq->property;
4869 #ifdef USE_XIM
4870 		if (freect)
4871 			XFree(ct.value);
4872 #endif
4873 	}
4874 	XSendEvent(r->Xdisplay, rq->requestor, False, 0L, (XEvent *)&ev);
4875 }
4876 
4877 /* ------------------------------------------------------------------------- *
4878  *							  MOUSE ROUTINES							   *
4879  * ------------------------------------------------------------------------- */
4880 
4881 /*
4882  * return col/row values corresponding to x/y pixel values
4883  */
4884 /* EXTPROTO */
4885 void
4886 rxvt_pixel_position(rxvt_t* r, int *x, int *y)
4887 {
4888 #ifdef THAI
4889 	if (r->Options & Opt_thai)
4890 		*x = ThaiPixel2Col(r, ATAB(r), *x, *y);
4891 	else
4892 #endif	/* THAI */
4893 	*x = Pixel2Col(*x);
4894 /* MAX_IT(*x, 0); MIN_IT(*x, (int)r->TermWin.ncol - 1); */
4895 	*y = Pixel2Row(*y);
4896 /* MAX_IT(*y, 0); MIN_IT(*y, (int)r->TermWin.nrow - 1); */
4897 }
4898 
4899 
4900 /* ------------------------------------------------------------------------- */
4901 #ifdef USE_XIM
4902 /* EXTPROTO */
4903 void
4904 rxvt_setPosition(rxvt_t* r, XPoint *pos)
4905 {
4906 	XWindowAttributes xwa;
4907 
4908 	XGetWindowAttributes(r->Xdisplay, AVTS(r)->vt, &xwa);
4909 	pos->x = Col2Pixel(ASCR(r).cur.col) + xwa.x;
4910 	pos->y = Height2Pixel((ASCR(r).cur.row + 1)) + xwa.y;
4911 #ifndef NO_LINESPACE
4912 	pos->y -= r->TermWin.lineSpace;
4913 #endif
4914 }
4915 #endif
4916 /* ------------------------------------------------------------------------- */
4917 
4918 /* ------------------------------------------------------------------------- *
4919  *							  DEBUG ROUTINES							   *
4920  * ------------------------------------------------------------------------- */
4921 #if 0
4922 /* INTPROTO */
4923 void
4924 rxvt_debug_colors(void)
4925 {
4926 	int			 color;
4927 	const char	 *name[] = {
4928 	"fg", "bg",
4929 	"black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"
4930 	};
4931 
4932 	fprintf(stderr, "Color ( ");
4933 	if (PVTS(r, page)->rstyle & RS_RVid)
4934 	fprintf(stderr, "rvid ");
4935 	if (PVTS(r, page)->rstyle & RS_Bold)
4936 	fprintf(stderr, "bold ");
4937 	if (PVTS(r, page)->rstyle & RS_Blink)
4938 	fprintf(stderr, "blink ");
4939 	if (PVTS(r, page)->rstyle & RS_Uline)
4940 	fprintf(stderr, "uline ");
4941 	fprintf(stderr, "): ");
4942 
4943 	color = GET_FGCOLOR(PVTS(r, page)->rstyle);
4944 #ifndef NO_BRIGHTCOLOR
4945 	if (color >= minBrightCOLOR && color <= maxBrightCOLOR) {
4946 	color -= (minBrightCOLOR - minCOLOR);
4947 	fprintf(stderr, "bright ");
4948 	}
4949 #endif
4950 	fprintf(stderr, "%s on ", name[color]);
4951 
4952 	color = GET_BGCOLOR(PVTS(r, page)->rstyle);
4953 #ifndef NO_BRIGHTCOLOR
4954 	if (color >= minBrightCOLOR && color <= maxBrightCOLOR) {
4955 	color -= (minBrightCOLOR - minCOLOR);
4956 	fprintf(stderr, "bright ");
4957 	}
4958 #endif
4959 	fprintf(stderr, "%s\n", name[color]);
4960 }
4961 #endif
4962 /*----------------------- end-of-file (C source) -----------------------*/
4963