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