ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/screen.C
(Generate patch)

Comparing rxvt-unicode/src/screen.C (file contents):
Revision 1.104 by root, Tue Aug 17 01:29:12 2004 UTC vs.
Revision 1.190 by root, Thu Dec 22 15:52:57 2005 UTC

23/* 23/*
24 * This file handles _all_ screen updates and selections 24 * This file handles _all_ screen updates and selections
25 */ 25 */
26 26
27#include "../config.h" /* NECESSARY */ 27#include "../config.h" /* NECESSARY */
28#define INTERN_SCREEN
29#include "rxvt.h" /* NECESSARY */ 28#include "rxvt.h" /* NECESSARY */
30 29
31#include <X11/Xmd.h> /* get the typedef for CARD32 */ 30#include <X11/Xmd.h> /* get the typedef for CARD32 */
32 31
33#include <inttypes.h> 32#include <inttypes.h>
34#include <wchar.h>
35 33
36#include "salloc.C" // HACK, should be a seperate compile! 34#include "salloc.C" // HACK, should be a seperate compile!
37 35
38inline void fill_text (text_t *start, text_t value, int len) 36inline void fill_text (text_t *start, text_t value, int len)
39{ 37{
40 while (len--) 38 while (len--)
41 *start++ = value; 39 *start++ = value;
42} 40}
43 41
44/* ------------------------------------------------------------------------- */ 42/* ------------------------------------------------------------------------- */
45#define PROP_SIZE 16384 43#define PROP_SIZE 256*1024
44#define PASTE_SIZE 32768
46#define TABSIZE 8 /* default tab size */ 45#define TABSIZE 8 /* default tab size */
47 46
48/* ------------------------------------------------------------------------- * 47/* ------------------------------------------------------------------------- *
49 * GENERAL SCREEN AND SELECTION UPDATE ROUTINES * 48 * GENERAL SCREEN AND SELECTION UPDATE ROUTINES *
50 * ------------------------------------------------------------------------- */ 49 * ------------------------------------------------------------------------- */
51#define ZERO_SCROLLBACK() \ 50#define ZERO_SCROLLBACK() \
52 if (options & Opt_scrollTtyOutput) \ 51 if (options & Opt_scrollTtyOutput) \
53 TermWin.view_start = 0 52 view_start = 0
54#define CLEAR_SELECTION() \ 53#define CLEAR_SELECTION() \
55 selection.beg.row = selection.beg.col \ 54 selection.beg.row = selection.beg.col \
56 = selection.end.row = selection.end.col = 0 55 = selection.end.row = selection.end.col = 0
57#define CLEAR_ALL_SELECTION() \ 56#define CLEAR_ALL_SELECTION() \
58 selection.beg.row = selection.beg.col \ 57 selection.beg.row = selection.beg.col \
89/* 88/*
90 * CLEAR_ROWS : clear <num> rows starting from row <row> 89 * CLEAR_ROWS : clear <num> rows starting from row <row>
91 * CLEAR_CHARS: clear <num> chars starting from pixel position <x,y> 90 * CLEAR_CHARS: clear <num> chars starting from pixel position <x,y>
92 * ERASE_ROWS : set <num> rows starting from row <row> to the foreground colour 91 * ERASE_ROWS : set <num> rows starting from row <row> to the foreground colour
93 */ 92 */
94#define drawBuffer TermWin.vt 93#define drawBuffer vt
95 94
96#define CLEAR_ROWS(row, num) \ 95#define CLEAR_ROWS(row, num) \
97 if (TermWin.mapped) \ 96 if (mapped) \
98 XClearArea (display->display, drawBuffer, 0, \ 97 XClearArea (display->display, drawBuffer, 0, \
99 Row2Pixel (row), (unsigned int)TermWin.width, \ 98 Row2Pixel (row), (unsigned int)width, \
100 (unsigned int)Height2Pixel (num), False) 99 (unsigned int)Height2Pixel (num), False)
101 100
102#define CLEAR_CHARS(x, y, num) \ 101#define CLEAR_CHARS(x, y, num) \
103 if (TermWin.mapped) \ 102 if (mapped) \
104 XClearArea (display->display, drawBuffer, x, y, \ 103 XClearArea (display->display, drawBuffer, x, y, \
105 (unsigned int)Width2Pixel (num), \ 104 (unsigned int)Width2Pixel (num), \
106 (unsigned int)Height2Pixel (1), False) 105 (unsigned int)Height2Pixel (1), False)
107 106
108#define ERASE_ROWS(row, num) \ 107#define ERASE_ROWS(row, num) \
109 XFillRectangle (display->display, drawBuffer, TermWin.gc, \ 108 XFillRectangle (display->display, drawBuffer, gc, \
110 0, Row2Pixel (row), \ 109 0, Row2Pixel (row), \
111 (unsigned int)TermWin.width, \ 110 (unsigned int)width, \
112 (unsigned int)Height2Pixel (num)) 111 (unsigned int)Height2Pixel (num))
113 112
114/* ------------------------------------------------------------------------- * 113/* ------------------------------------------------------------------------- *
115 * SCREEN `COMMON' ROUTINES * 114 * SCREEN `COMMON' ROUTINES *
116 * ------------------------------------------------------------------------- */ 115 * ------------------------------------------------------------------------- */
116
117/* Fill part/all of a line with blanks. */ 117/* Fill part/all of a line with blanks. */
118void 118void
119rxvt_term::scr_blank_line (text_t *et, rend_t *er, unsigned int width, rend_t efs) 119rxvt_term::scr_blank_line (line_t &l, unsigned int col, unsigned int width, rend_t efs)
120{ 120{
121 if (!l.t)
122 {
123 lalloc (l);
124 col = 0;
125 width = ncol;
126 }
127
121 efs &= ~RS_baseattrMask; 128 efs &= ~RS_baseattrMask;
122 efs = SET_FONT (efs, TermWin.ascii_map [' ' - 0x20]); 129 efs = SET_FONT (efs, FONTSET (efs)->find_font (' '));
130
131 text_t *et = l.t + col;
132 rend_t *er = l.r + col;
123 133
124 while (width--) 134 while (width--)
125 { 135 {
126 *et++ = ' '; 136 *et++ = ' ';
127 *er++ = efs; 137 *er++ = efs;
129} 139}
130 140
131/* ------------------------------------------------------------------------- */ 141/* ------------------------------------------------------------------------- */
132/* Fill a full line with blanks - make sure it is allocated first */ 142/* Fill a full line with blanks - make sure it is allocated first */
133void 143void
134rxvt_term::scr_blank_screen_mem (text_t **tp, rend_t **rp, unsigned int row, rend_t efs) 144rxvt_term::scr_blank_screen_mem (line_t &l, rend_t efs)
135{ 145{
136#ifdef DEBUG_STRICT 146 scr_blank_line (l, 0, ncol, efs);
137 assert ((tp[row] && rp[row]) || (tp[row] == NULL && rp[row] == NULL));
138#endif
139 if (tp[row] == NULL)
140 {
141 tp[row] = (text_t *)talloc->alloc ();
142 rp[row] = (rend_t *)ralloc->alloc ();
143 }
144
145 scr_blank_line (tp[row], rp[row], TermWin.ncol, efs);
146} 147}
147 148
148/* ------------------------------------------------------------------------- * 149/* ------------------------------------------------------------------------- *
149 * SCREEN INITIALISATION * 150 * SCREEN INITIALISATION *
150 * ------------------------------------------------------------------------- */ 151 * ------------------------------------------------------------------------- */
152
151void 153void
152rxvt_term::scr_reset () 154rxvt_term::scr_reset ()
153{ 155{
154 unsigned int ncol, nrow, total_rows, prev_total_rows;
155 unsigned int p, q;
156 int k;
157 rend_t setrstyle;
158
159#if ENABLE_OVERLAY 156#if ENABLE_OVERLAY
160 scr_overlay_off (); 157 scr_overlay_off ();
161#endif 158#endif
162 159
163 TermWin.view_start = 0; 160 view_start = 0;
164 num_scr = 0; 161 num_scr = 0;
165 162
166 if (TermWin.ncol == 0) 163 if (ncol == 0)
167 TermWin.ncol = 80; 164 ncol = 80;
168 165
169 if (TermWin.nrow == 0) 166 if (nrow == 0)
170 TermWin.nrow = 24; 167 nrow = 24;
171
172 ncol = TermWin.ncol;
173 nrow = TermWin.nrow;
174 168
175 if (ncol == prev_ncol && nrow == prev_nrow) 169 if (ncol == prev_ncol && nrow == prev_nrow)
176 return; 170 return;
177 171
178 // we need at least two lines for wrapping to work correctly 172 // we need at least two lines for wrapping to work correctly
179 if (nrow + TermWin.saveLines < 2) 173 if (nrow + saveLines < 2)
180 { 174 {
175 //TODO//FIXME
181 TermWin.saveLines++; 176 saveLines++;
182 prev_nrow--; 177 prev_nrow--;
183 TermWin.nscrolled++; 178 nsaved++;
184 } 179 }
185 180
186 want_refresh = 1; 181 want_refresh = 1;
187 182
188 prev_total_rows = prev_nrow + TermWin.saveLines; 183 int prev_total_rows = prev_nrow + saveLines;
189 total_rows = nrow + TermWin.saveLines; 184 total_rows = nrow + saveLines;
190 185
191 screen.tscroll = 0; 186 screen.tscroll = 0;
192 screen.bscroll = nrow - 1; 187 screen.bscroll = nrow - 1;
193 188
194 if (!talloc) 189 if (!row_buf)
195 {
196 talloc = new rxvt_salloc (ncol * sizeof (text_t));
197 ralloc = new rxvt_salloc (ncol * sizeof (rend_t));
198 }
199
200 if (!screen.text)
201 { 190 {
202 /* 191 /*
203 * first time called so just malloc everything: don't rely on realloc 192 * first time called so just malloc everything: don't rely on realloc
204 * Note: this is still needed so that all the scrollback lines are NULL 193 * Note: this is still needed so that all the scrollback lines are NULL
205 */ 194 */
195 nsaved = 0; /* no saved lines */
196 term_start = 0;
197
198 talloc = new rxvt_salloc (ncol * sizeof (text_t));
199 ralloc = new rxvt_salloc (ncol * sizeof (rend_t));
200
201 row_buf = (line_t *)rxvt_calloc (total_rows, sizeof (line_t));
206 screen.text = (text_t **)rxvt_calloc (total_rows, sizeof (text_t *)); 202 temp_buf = (line_t *)rxvt_calloc (total_rows, sizeof (line_t));
207 buf_text = (text_t **)rxvt_calloc (total_rows, sizeof (text_t *)); 203 drawn_buf = (line_t *)rxvt_calloc (nrow , sizeof (line_t));
208 drawn_text = (text_t **)rxvt_calloc (nrow, sizeof (text_t *));
209 swap.text = (text_t **)rxvt_calloc (nrow, sizeof (text_t *));
210
211 screen.tlen = (int16_t *)rxvt_calloc (total_rows, sizeof (int16_t));
212 swap.tlen = (int16_t *)rxvt_calloc (nrow, sizeof (int16_t)); 204 swap_buf = (line_t *)rxvt_calloc (nrow , sizeof (line_t));
213 205
214 screen.rend = (rend_t **)rxvt_calloc (total_rows, sizeof (rend_t *)); 206 for (int row = nrow; row--; )
215 buf_rend = (rend_t **)rxvt_calloc (total_rows, sizeof (rend_t *));
216 drawn_rend = (rend_t **)rxvt_calloc (nrow, sizeof (rend_t *));
217 swap.rend = (rend_t **)rxvt_calloc (nrow, sizeof (rend_t *));
218
219 for (p = 0; p < nrow; p++)
220 { 207 {
221 q = p + TermWin.saveLines;
222 scr_blank_screen_mem (screen.text, screen.rend, q, DEFAULT_RSTYLE); 208 scr_blank_screen_mem (ROW (row), DEFAULT_RSTYLE);
223 scr_blank_screen_mem (swap.text, swap.rend, p, DEFAULT_RSTYLE); 209 scr_blank_screen_mem (swap_buf [row], DEFAULT_RSTYLE);
224 screen.tlen[q] = swap.tlen[p] = 0;
225 scr_blank_screen_mem (drawn_text, drawn_rend, p, DEFAULT_RSTYLE); 210 scr_blank_screen_mem (drawn_buf[row], DEFAULT_RSTYLE);
226 } 211 }
227 212
228 memset (charsets, 'B', sizeof (charsets)); 213 memset (charsets, 'B', sizeof (charsets));
229 TermWin.nscrolled = 0; /* no saved lines */
230 rstyle = DEFAULT_RSTYLE; 214 rstyle = DEFAULT_RSTYLE;
231 screen.flags = Screen_DefaultFlags; 215 screen.flags = Screen_DefaultFlags;
232 screen.cur.row = screen.cur.col = 0; 216 screen.cur.row = screen.cur.col = 0;
233 screen.charset = 0; 217 screen.charset = 0;
234 current_screen = PRIMARY; 218 current_screen = PRIMARY;
254 else 238 else
255 { 239 {
256 /* 240 /*
257 * add or delete rows as appropriate 241 * add or delete rows as appropriate
258 */ 242 */
259 setrstyle = DEFAULT_RSTYLE;
260 243
244 rxvt_salloc *old_ta = talloc; talloc = new rxvt_salloc (ncol * sizeof (text_t));
245 rxvt_salloc *old_ra = ralloc; ralloc = new rxvt_salloc (ncol * sizeof (rend_t));
246
247#if 0
261 if (nrow < prev_nrow) 248 if (nrow < prev_nrow)
262 { 249 {
263 /* delete rows */
264 k = min (TermWin.nscrolled, prev_nrow - nrow);
265 scr_scroll_text (0, (int)prev_nrow - 1, k, 1);
266
267 for (p = nrow; p < prev_nrow; p++) 250 for (int row = nrow; row < prev_nrow; row++)
268 { 251 {
269 q = p + TermWin.saveLines; 252 lfree (swap_buf [row]);
253 lfree (drawn_buf[row]);
254 }
255 }
256#endif
270 257
271 if (screen.text[q]) 258 drawn_buf = (line_t *)rxvt_realloc (drawn_buf, nrow * sizeof (line_t));
259 temp_buf = (line_t *)rxvt_realloc (temp_buf , nrow * sizeof (line_t));
260 swap_buf = (line_t *)rxvt_realloc (swap_buf , nrow * sizeof (line_t));
261
262 for (int row = min (nrow, prev_nrow); row--; )
263 {
264 lresize (drawn_buf[row]);
265 lresize (swap_buf [row]);
266 }
267
268 for (int row = prev_nrow; row < nrow; row++)
269 {
270 swap_buf [row].clear (); scr_blank_screen_mem (swap_buf [row], DEFAULT_RSTYLE);
271 drawn_buf[row].clear (); scr_blank_screen_mem (drawn_buf[row], DEFAULT_RSTYLE);
272 }
273
274 line_t *old_buf = row_buf; row_buf = (line_t *)rxvt_calloc (total_rows, sizeof (line_t));
275
276 int p = MOD (term_start + prev_nrow, prev_total_rows); // previous row
277 int pend = MOD (term_start - nsaved , prev_total_rows);
278 int q = total_rows; // rewrapped row
279
280 if (nsaved)
281 {
282 // re-wrap lines, this is rather ugly, possibly because I am too dumb
283 // to come up with a lean and mean algorithm.
284
285 row_col_t ocur = screen.cur;
286 ocur.row = MOD (term_start + ocur.row, prev_total_rows);
287
288 while (p != pend && q > 0)
289 {
290 p = MOD (p - 1, prev_total_rows);
291#ifdef DEBUG_STRICT
292 assert (old_buf [MOD (p, prev_total_rows)].t);
293#endif
294
295 int plines = 1;
296 int llen = old_buf [MOD (p, prev_total_rows)].l;
297
298 while (p != pend && old_buf [MOD (p - 1, prev_total_rows)].is_longer ())
272 { 299 {
300 p = MOD (p - 1, prev_total_rows);
301
302 plines++;
303 llen += prev_ncol;
304 }
305
306 int qlines = max (0, (llen - 1) / ncol) + 1;
307
308 // drop partial lines completely
309 if (q < qlines)
310 break;
311
312 q -= qlines;
313
314 int lofs = 0;
315 line_t *qline;
316
317 // re-assemble the full line by destination lines
318 for (int qrow = q; qlines--; qrow++)
319 {
320 qline = row_buf + qrow;
321 lalloc (*qline);
322 qline->set_is_longer ();
323
324 int qcol = 0;
325
326 // fill a single destination line
327 while (lofs < llen && qcol < ncol)
328 {
329 int prow = lofs / prev_ncol;
330 int pcol = lofs % prev_ncol;
331
332 prow = MOD (p + prow, prev_total_rows);
333
334 // we only adjust the cursor _row_, as this seems to upset
335 // applications/shells/readline least.
336 if (prow == ocur.row)
337 screen.cur.row = qrow - (total_rows - nrow);
338
339 line_t &pline = old_buf [prow];
340
341 int len = min (min (prev_ncol - pcol, ncol - qcol), llen - lofs);
342
343 assert (len);
344 assert (pline.t);
345
346 memcpy (qline->t + qcol, pline.t + pcol, len * sizeof (text_t));
347 memcpy (qline->r + qcol, pline.r + pcol, len * sizeof (rend_t));
348
349 lofs += len;
350 qcol += len;
351 }
352 }
353
354 qline->l = llen < ncol ? llen : MOD (llen - 1, ncol) + 1;
355 scr_blank_line (*qline, qline->l, ncol - qline->l, DEFAULT_RSTYLE);
356 }
357
358 term_start = total_rows - nrow;
359 view_start = 0;
360 nsaved = term_start - q;
361
362 // make sure all terminal lines exist
363 while (nsaved < 0)
364 scr_blank_screen_mem (ROW (-++nsaved), DEFAULT_RSTYLE);
365
366 }
367 else
368 {
369 // if no scrollback exists (yet), wing, instead of wrap
370
371 for (int row = min (nrow, prev_nrow); row--; )
372 {
373 line_t &pline = old_buf [MOD (term_start + row, prev_total_rows)];
374 line_t &qline = row_buf [row];
375
376 qline = pline;
377 lresize (qline);
378 }
379
380 for (int row = prev_nrow; row < nrow; row++)
381 {
382 row_buf [row].clear (); scr_blank_screen_mem (row_buf [row], DEFAULT_RSTYLE);
383 }
384
385 term_start = 0;
386 view_start = 0;
387 }
388
273#ifdef DEBUG_STRICT 389#ifdef DEBUG_STRICT
274 assert (screen.rend[q]); 390 for (int i = -nsaved; i < nrow; i++)
391 assert (ROW (i).t);
275#endif 392#endif
276 talloc->free (screen.text[q]);
277 ralloc->free (screen.rend[q]);
278 }
279 393
280 if (swap.text[p]) 394 free (old_buf);
281 { 395 delete old_ta;
282#ifdef DEBUG_STRICT 396 delete old_ra;
283 assert (swap.rend[p]);
284#endif
285 talloc->free (swap.text[p]);
286 ralloc->free (swap.rend[p]);
287 }
288 397
289#ifdef DEBUG_STRICT
290 assert (drawn_text[p] && drawn_rend[p]);
291#endif
292 talloc->free (drawn_text[p]);
293 ralloc->free (drawn_rend[p]);
294 }
295
296 /* we have fewer rows so fix up cursor position */
297 MIN_IT (screen.cur.row, (int32_t)nrow - 1);
298 MIN_IT (swap.cur.row, (int32_t)nrow - 1);
299
300 scr_reset_realloc (); /* realloc _last_ */
301 }
302 else if (nrow > prev_nrow)
303 {
304 /* add rows */
305 scr_reset_realloc (); /* realloc _first_ */
306
307 TermWin.ncol = prev_ncol; // save b/c scr_blank_screen_mem uses this
308
309 k = min (TermWin.nscrolled, nrow - prev_nrow);
310
311 for (p = prev_total_rows; p < total_rows; p++)
312 {
313 screen.tlen[p] = 0;
314 screen.text[p] = NULL;
315 screen.rend[p] = NULL;
316 }
317
318 for (p = prev_total_rows; p < total_rows - k; p++)
319 scr_blank_screen_mem (screen.text, screen.rend, p, setrstyle);
320
321 for (p = prev_nrow; p < nrow; p++)
322 {
323 swap.tlen[p] = 0;
324 swap.text[p] = NULL;
325 swap.rend[p] = NULL;
326 drawn_text[p] = NULL;
327 drawn_rend[p] = NULL;
328 scr_blank_screen_mem (swap.text, swap.rend, p, setrstyle);
329 scr_blank_screen_mem (drawn_text, drawn_rend, p, setrstyle);
330 }
331
332 if (k > 0)
333 {
334 scr_scroll_text (0, (int)nrow - 1, -k, 1);
335 screen.cur.row += k;
336 screen.s_cur.row += k;
337 TermWin.nscrolled -= k;
338 }
339#ifdef DEBUG_STRICT
340 assert (screen.cur.row < TermWin.nrow);
341 assert (swap.cur.row < TermWin.nrow);
342#else /* drive with your eyes closed */
343
344 MIN_IT (screen.cur.row, nrow - 1); 398 clamp_it (screen.cur.row, 0, nrow - 1);
345 MIN_IT (swap.cur.row, nrow - 1); 399 clamp_it (screen.cur.col, 0, ncol - 1);
346#endif
347 TermWin.ncol = ncol; // save b/c scr_blank_screen_mem uses this
348 }
349
350 /* resize columns */
351 if (ncol != prev_ncol)
352 {
353 rxvt_salloc *ta = new rxvt_salloc (ncol * sizeof (text_t));
354 rxvt_salloc *ra = new rxvt_salloc (ncol * sizeof (rend_t));
355
356 for (p = 0; p < total_rows; p++)
357 {
358 if (screen.text[p])
359 {
360 screen.text[p] = (text_t *)ta->alloc (screen.text[p], prev_ncol * sizeof (text_t));
361 screen.rend[p] = (rend_t *)ra->alloc (screen.rend[p], prev_ncol * sizeof (rend_t));
362
363 MIN_IT (screen.tlen[p], (int16_t)ncol);
364
365 if (ncol > prev_ncol)
366 scr_blank_line (&screen.text[p][prev_ncol],
367 &screen.rend[p][prev_ncol],
368 ncol - prev_ncol, setrstyle);
369 }
370 }
371
372 for (p = 0; p < nrow; p++)
373 {
374 drawn_text[p] = (text_t *)ta->alloc (drawn_text[p], prev_ncol * sizeof (text_t));
375 drawn_rend[p] = (rend_t *)ra->alloc (drawn_rend[p], prev_ncol * sizeof (rend_t));
376
377 if (ncol > prev_ncol)
378 scr_blank_line (&drawn_text[p][prev_ncol],
379 &drawn_rend[p][prev_ncol],
380 ncol - prev_ncol, setrstyle);
381
382 if (swap.text[p])
383 {
384 swap.text[p] = (text_t *)ta->alloc (swap.text[p], prev_ncol * sizeof (text_t));
385 swap.rend[p] = (rend_t *)ra->alloc (swap.rend[p], prev_ncol * sizeof (rend_t));
386
387 MIN_IT (swap.tlen[p], (int16_t)ncol);
388
389 if (ncol > prev_ncol)
390 scr_blank_line (&swap.text[p][prev_ncol],
391 &swap.rend[p][prev_ncol],
392 ncol - prev_ncol, setrstyle);
393 }
394
395 }
396
397 MIN_IT (screen.cur.col, (int16_t)ncol - 1);
398 MIN_IT (swap.cur.col, (int16_t)ncol - 1);
399
400 delete talloc; talloc = ta;
401 delete ralloc; ralloc = ra;
402 }
403 400
404 if (tabs) 401 if (tabs)
405 free (tabs); 402 free (tabs);
406 } 403 }
407 404
408 prev_nrow = nrow; 405 prev_nrow = nrow;
409 prev_ncol = ncol; 406 prev_ncol = ncol;
410 407
411 tabs = (char *)rxvt_malloc (ncol * sizeof (char)); 408 tabs = (char *)rxvt_malloc (ncol * sizeof (char));
412 409
413 for (p = 0; p < ncol; p++) 410 for (int col = ncol; col--; )
414 tabs[p] = (p % TABSIZE == 0) ? 1 : 0; 411 tabs [col] = col % TABSIZE == 0;
415 412
416 tt_winch (); 413 tt_winch ();
417} 414}
418 415
419void
420rxvt_term::scr_reset_realloc ()
421{
422 uint16_t total_rows, nrow;
423
424 nrow = TermWin.nrow;
425 total_rows = nrow + TermWin.saveLines;
426 /* *INDENT-OFF* */
427 screen.text = (text_t **)rxvt_realloc (screen.text, total_rows * sizeof (text_t *));
428 buf_text = (text_t **)rxvt_realloc (buf_text , total_rows * sizeof (text_t *));
429 drawn_text = (text_t **)rxvt_realloc (drawn_text , nrow * sizeof (text_t *));
430 swap.text = (text_t **)rxvt_realloc (swap.text , nrow * sizeof (text_t *));
431
432 screen.tlen = (int16_t *)rxvt_realloc (screen.tlen, total_rows * sizeof (int16_t));
433 swap.tlen = (int16_t *)rxvt_realloc (swap.tlen , total_rows * sizeof (int16_t));
434
435 screen.rend = (rend_t **)rxvt_realloc (screen.rend, total_rows * sizeof (rend_t *));
436 buf_rend = (rend_t **)rxvt_realloc (buf_rend , total_rows * sizeof (rend_t *));
437 drawn_rend = (rend_t **)rxvt_realloc (drawn_rend , nrow * sizeof (rend_t *));
438 swap.rend = (rend_t **)rxvt_realloc (swap.rend , nrow * sizeof (rend_t *));
439 /* *INDENT-ON* */
440}
441
442/* ------------------------------------------------------------------------- */ 416/* ------------------------------------------------------------------------- */
443/* 417/*
444 * Free everything. That way malloc debugging can find leakage. 418 * Free everything. That way malloc debugging can find leakage.
445 */ 419 */
446void 420void
447rxvt_term::scr_release () 421rxvt_term::scr_release ()
448{ 422{
449 uint16_t total_rows;
450 int i;
451
452 total_rows = TermWin.nrow + TermWin.saveLines;
453
454 delete talloc; talloc = 0; 423 delete talloc; talloc = 0;
455 delete ralloc; ralloc = 0; 424 delete ralloc; ralloc = 0;
456 425
457 free (screen.text); 426 free (row_buf);
458 free (screen.tlen); 427 free (swap_buf);
459 free (screen.rend);
460 free (drawn_text); 428 free (drawn_buf);
461 free (drawn_rend); 429 free (temp_buf);
462 free (swap.text);
463 free (swap.tlen);
464 free (swap.rend);
465 free (buf_text);
466 free (buf_rend);
467 free (tabs); 430 free (tabs);
468 431
469 /* NULL these so if anything tries to use them, we'll know about it */ 432 row_buf = 0; // signal that we freed all the arrays
470 screen.text = drawn_text = swap.text = NULL;
471 screen.rend = drawn_rend = swap.rend = NULL;
472 screen.tlen = swap.tlen = NULL;
473 buf_text = NULL;
474 buf_rend = NULL;
475 tabs = NULL;
476} 433}
477 434
478/* ------------------------------------------------------------------------- */ 435/* ------------------------------------------------------------------------- */
479/* 436/*
480 * Hard reset 437 * Hard reset
511 s = &screen; 468 s = &screen;
512 469
513 switch (mode) 470 switch (mode)
514 { 471 {
515 case SAVE: 472 case SAVE:
516 s->s_cur.row = s->cur.row; 473 s->s_cur.row = screen.cur.row;
517 s->s_cur.col = s->cur.col; 474 s->s_cur.col = screen.cur.col;
518 s->s_rstyle = rstyle; 475 s->s_rstyle = rstyle;
519 s->s_charset = s->charset; 476 s->s_charset = screen.charset;
520 s->s_charset_char = charsets[s->charset]; 477 s->s_charset_char = charsets[screen.charset];
521 break; 478 break;
522 479
523 case RESTORE: 480 case RESTORE:
524 want_refresh = 1; 481 want_refresh = 1;
525 s->cur.row = s->s_cur.row; 482 screen.cur.row = s->s_cur.row;
526 s->cur.col = s->s_cur.col; 483 screen.cur.col = s->s_cur.col;
527 s->flags &= ~Screen_WrapNext; 484 screen.flags &= ~Screen_WrapNext;
528 rstyle = s->s_rstyle; 485 rstyle = s->s_rstyle;
529 s->charset = s->s_charset; 486 screen.charset = s->s_charset;
530 charsets[s->charset] = s->s_charset_char; 487 charsets[screen.charset] = s->s_charset_char;
531 set_font_style (); 488 set_font_style ();
532 break; 489 break;
533 } 490 }
534 491
535 /* boundary check in case screen size changed between SAVE and RESTORE */ 492 /* boundary check in case screen size changed between SAVE and RESTORE */
536 MIN_IT (s->cur.row, TermWin.nrow - 1); 493 min_it (s->cur.row, nrow - 1);
537 MIN_IT (s->cur.col, TermWin.ncol - 1); 494 min_it (s->cur.col, ncol - 1);
538#ifdef DEBUG_STRICT 495#ifdef DEBUG_STRICT
539 assert (s->cur.row >= 0); 496 assert (s->cur.row >= 0);
540 assert (s->cur.col >= 0); 497 assert (s->cur.col >= 0);
541#else /* drive with your eyes closed */
542 MAX_IT (s->cur.row, 0);
543 MAX_IT (s->cur.col, 0);
544#endif 498#endif
545} 499}
546 500
547/* ------------------------------------------------------------------------- */ 501/* ------------------------------------------------------------------------- */
548/* 502/*
551 * XTERM_SEQ: Secondary screen: ESC [ ? 4 7 l 505 * XTERM_SEQ: Secondary screen: ESC [ ? 4 7 l
552 */ 506 */
553int 507int
554rxvt_term::scr_change_screen (int scrn) 508rxvt_term::scr_change_screen (int scrn)
555{ 509{
556 int i;
557#if NSCREENS
558 int offset;
559#endif
560
561 want_refresh = 1; 510 want_refresh = 1;
562
563 TermWin.view_start = 0; 511 view_start = 0;
564 512
565 if (current_screen == scrn) 513 if (current_screen == scrn)
566 return scrn; 514 return scrn;
567 515
568 selection_check (2); /* check for boundary cross */ 516 selection_check (2); /* check for boundary cross */
569 517
570 SWAP_IT (current_screen, scrn, int); 518 int i = current_screen; current_screen = scrn; scrn = i;
519
520 ::swap (screen.cur.row, swap.cur.row);
521 ::swap (screen.cur.col, swap.cur.col);
522
523 screen.cur.row = clamp (screen.cur.row, 0, prev_nrow - 1);
524 screen.cur.col = clamp (screen.cur.col, 0, prev_ncol - 1);
525
571#if NSCREENS 526#if NSCREENS
572 if (options & Opt_secondaryScreen) 527 if (options & Opt_secondaryScreen)
573 { 528 {
574 num_scr = 0; 529 num_scr = 0;
575 offset = TermWin.saveLines; 530
576 for (i = prev_nrow; i--;) 531 for (int i = prev_nrow; i--; )
577 { 532 ::swap (ROW(i), swap_buf [i]);
578 SWAP_IT (screen.text[i + offset], swap.text[i], text_t *); 533
579 SWAP_IT (screen.tlen[i + offset], swap.tlen[i], int16_t);
580 SWAP_IT (screen.rend[i + offset], swap.rend[i], rend_t *);
581 }
582 SWAP_IT (screen.cur.row, swap.cur.row, int16_t);
583 SWAP_IT (screen.cur.col, swap.cur.col, int16_t);
584# ifdef DEBUG_STRICT
585 assert ((screen.cur.row >= 0) && (screen.cur.row < prev_nrow));
586 assert ((screen.cur.col >= 0) && (screen.cur.col < prev_ncol));
587# else /* drive with your eyes closed */
588 MAX_IT (screen.cur.row, 0);
589 MIN_IT (screen.cur.row, (int32_t)prev_nrow - 1);
590 MAX_IT (screen.cur.col, 0);
591 MIN_IT (screen.cur.col, (int32_t)prev_ncol - 1);
592# endif
593 SWAP_IT (screen.charset, swap.charset, int16_t); 534 ::swap (screen.charset, swap.charset);
594 SWAP_IT (screen.flags, swap.flags, int); 535 ::swap (screen.flags, swap.flags);
595 screen.flags |= Screen_VisibleCursor; 536 screen.flags |= Screen_VisibleCursor;
596 swap.flags |= Screen_VisibleCursor; 537 swap.flags |= Screen_VisibleCursor;
597 } 538 }
598 else 539 else
599#endif 540#endif
600 if (options & Opt_secondaryScroll) 541 if (options & Opt_secondaryScroll)
601 //if (current_screen == PRIMARY)
602 scr_scroll_text (0, (prev_nrow - 1), prev_nrow, 0); 542 scr_scroll_text (0, prev_nrow - 1, prev_nrow);
543
603 return scrn; 544 return scrn;
604} 545}
605 546
606// clear WrapNext indicator, solidifying position on next line 547// clear WrapNext indicator, solidifying position on next line
607void 548void
613 screen.flags &= ~Screen_WrapNext; 554 screen.flags &= ~Screen_WrapNext;
614 555
615 screen.cur.col = 0; 556 screen.cur.col = 0;
616 557
617 if (screen.cur.row == screen.bscroll) 558 if (screen.cur.row == screen.bscroll)
618 scr_scroll_text (screen.tscroll, screen.bscroll, 1, 0); 559 scr_scroll_text (screen.tscroll, screen.bscroll, 1);
619 else if (screen.cur.row < TermWin.nrow - 1) 560 else if (screen.cur.row < nrow - 1)
620 screen.cur.row++; 561 screen.cur.row++;
621} 562}
622 563
623/* ------------------------------------------------------------------------- */ 564/* ------------------------------------------------------------------------- */
624/* 565/*
625 * Change the colour for following text 566 * Change the colour for following text
626 */ 567 */
627void 568void
628rxvt_term::scr_color (unsigned int color, int fgbg) 569rxvt_term::scr_color (unsigned int color, int fgbg)
629{ 570{
630 color &= RS_fgMask; 571 if (color > maxTermCOLOR)
572 color = fgbg;
573
631 if (fgbg == Color_fg) 574 if (fgbg == Color_fg)
632 rstyle = SET_FGCOLOR (rstyle, color); 575 rstyle = SET_FGCOLOR (rstyle, color);
633 else 576 else
634 rstyle = SET_BGCOLOR (rstyle, color); 577 rstyle = SET_BGCOLOR (rstyle, color);
635} 578}
652/* ------------------------------------------------------------------------- */ 595/* ------------------------------------------------------------------------- */
653/* 596/*
654 * Scroll text between <row1> and <row2> inclusive, by <count> lines 597 * Scroll text between <row1> and <row2> inclusive, by <count> lines
655 * count positive ==> scroll up 598 * count positive ==> scroll up
656 * count negative ==> scroll down 599 * count negative ==> scroll down
657 * spec == 0 for normal routines
658 */ 600 */
659int 601int
660rxvt_term::scr_scroll_text (int row1, int row2, int count, int spec) 602rxvt_term::scr_scroll_text (int row1, int row2, int count)
661{ 603{
662 int i, j;
663 long nscrolled;
664
665 if (count == 0 || (row1 > row2)) 604 if (count == 0 || (row1 > row2))
666 return 0; 605 return 0;
667 606
668 want_refresh = 1; 607 want_refresh = 1;
608 num_scr += count;
669 609
670 if (row1 == 0 && count > 0 610 if (count > 0
611 && row1 == 0
612 && row2 == nrow - 1
671 && (current_screen == PRIMARY || options & Opt_secondaryScroll)) 613 && (current_screen == PRIMARY || options & Opt_secondaryScroll))
672 { 614 {
673 nscrolled = (long)TermWin.nscrolled + (long)count; 615 nsaved = min (nsaved + count, saveLines);
616 term_start = (term_start + count) % total_rows;
674 617
675 if (nscrolled > (long)TermWin.saveLines) 618 if (selection.op && current_screen == selection.screen)
676 TermWin.nscrolled = TermWin.saveLines; 619 {
620 selection.beg.row -= count;
621 selection.end.row -= count;
622 selection.mark.row -= count;
623
624 selection_check (0);
625 }
626
627 for (int i = count; i--; )
628 scr_blank_screen_mem (ROW(row2 - i), rstyle);
677 else 629
678 TermWin.nscrolled = (uint16_t)nscrolled;
679
680 if ((options & Opt_scrollWithBuffer) 630 if ((options & Opt_scrollWithBuffer)
681 && TermWin.view_start != 0 631 && view_start != 0
682 && TermWin.view_start != TermWin.saveLines) 632 && view_start != saveLines)
683 scr_page (UP, count); 633 scr_page (UP, count);
684 } 634 }
685 else if (!spec) 635 else
686 row1 += TermWin.saveLines; 636 {
687
688 row2 += TermWin.saveLines;
689
690 if (selection.op && current_screen == selection.screen) 637 if (selection.op && current_screen == selection.screen)
691 { 638 {
692 i = selection.beg.row + TermWin.saveLines; 639 int i = selection.beg.row;
693 j = selection.end.row + TermWin.saveLines; 640 int j = selection.end.row;
641
694 if ((i < row1 && j > row1) 642 if ((i < row1 && j > row1)
695 || (i < row2 && j > row2) 643 || (i < row2 && j > row2)
696 || (i - count < row1 && i >= row1) 644 || (i - count < row1 && i >= row1)
697 || (i - count > row2 && i <= row2) 645 || (i - count > row2 && i <= row2)
698 || (j - count < row1 && j >= row1) 646 || (j - count < row1 && j >= row1)
699 || (j - count > row2 && j <= row2)) 647 || (j - count > row2 && j <= row2))
700 { 648 {
701 CLEAR_ALL_SELECTION (); 649 CLEAR_ALL_SELECTION ();
702 selection.op = SELECTION_CLEAR; /* XXX: too aggressive? */ 650 selection.op = SELECTION_CLEAR; /* XXX: too aggressive? */
703 } 651 }
704 else if (j >= row1 && j <= row2) 652 else if (j >= row1 && j <= row2)
705 { 653 {
706 /* move selected region too */ 654 /* move selected region too */
707 selection.beg.row -= count; 655 selection.beg.row -= count;
708 selection.end.row -= count; 656 selection.end.row -= count;
709 selection.mark.row -= count; 657 selection.mark.row -= count;
658
659 selection_check (0);
710 } 660 }
711 }
712
713 selection_check (0); /* _after_ TermWin.nscrolled update */
714
715 num_scr += count;
716 j = count;
717
718 if (count < 0)
719 count = -count;
720
721 i = row2 - row1 + 1;
722 MIN_IT (count, i);
723
724 if (j > 0)
725 {
726 /* A: scroll up */
727
728 /* A1: Copy lines that will get clobbered by the rotation */
729 memcpy (buf_text, screen.text + row1, count * sizeof (text_t *));
730 memcpy (buf_rend, screen.rend + row1, count * sizeof (rend_t *));
731
732 /* A2: Rotate lines */
733 i = row2 - row1 - count + 1;
734 memmove (screen.tlen + row1, screen.tlen + row1 + count, i * sizeof (int16_t));
735 memmove (screen.text + row1, screen.text + row1 + count, i * sizeof (text_t *));
736 memmove (screen.rend + row1, screen.rend + row1 + count, i * sizeof (rend_t *));
737
738 j = row2 - count + 1, i = count;
739 }
740 else /* if (j < 0) */
741 {
742 /* B: scroll down */
743
744 /* B1: Copy lines that will get clobbered by the rotation */
745 for (i = 0, j = row2; i < count; i++, j--)
746 { 661 }
747 buf_text[i] = screen.text[j]; 662
748 buf_rend[i] = screen.rend[j]; 663 // use a simple and robust scrolling algorithm, this
664 // part of scr_scroll_text is not time-critical.
665
666 int rows = row2 - row1 + 1;
667
668 min_it (count, rows);
669
670 for (int row = 0; row < rows; row++)
749 } 671 {
672 temp_buf [row] = ROW(row1 + (row + count + rows) % rows);
750 673
751 /* B2: Rotate lines */ 674 if (!IN_RANGE_EXC (row + count, 0, rows))
752 for (j = row2, i = j - count; i >= row1; i--, j--) 675 scr_blank_screen_mem (temp_buf [row], rstyle);
753 { 676 }
754 screen.tlen[j] = screen.tlen[i];
755 screen.text[j] = screen.text[i];
756 screen.rend[j] = screen.rend[i];
757 }
758 677
759 j = row1, i = count; 678 for (int row = 0; row < rows; row++)
760 count = -count; 679 ROW(row1 + row) = temp_buf [row];
761 } 680 }
762
763 /* C: Resurrect lines */
764 memset (screen.tlen + j, 0, i * sizeof (int16_t));
765 memcpy (screen.text + j, buf_text, i * sizeof (text_t *));
766 memcpy (screen.rend + j, buf_rend, i * sizeof (text_t *));
767 if (!spec) /* line length may not equal TermWin.ncol */
768 for (; i--; j++)
769 scr_blank_screen_mem (screen.text, screen.rend, (unsigned int)j, rstyle);
770 681
771 return count; 682 return count;
772} 683}
773 684
774/* ------------------------------------------------------------------------- */ 685/* ------------------------------------------------------------------------- */
776 * Add text given in <str> of length <len> to screen struct 687 * Add text given in <str> of length <len> to screen struct
777 */ 688 */
778void 689void
779rxvt_term::scr_add_lines (const unicode_t *str, int nlines, int len) 690rxvt_term::scr_add_lines (const unicode_t *str, int nlines, int len)
780{ 691{
692 if (len <= 0) /* sanity */
693 return;
694
781 unsigned char checksel; 695 unsigned char checksel;
782 unicode_t c; 696 unicode_t c;
783 int i, row, last_col; 697 int row, last_col;
784 text_t *stp; 698 const unicode_t *strend = str + len;
785 rend_t *srp;
786
787 if (len <= 0) /* sanity */
788 return;
789 699
790 want_refresh = 1; 700 want_refresh = 1;
791 ZERO_SCROLLBACK (); 701 ZERO_SCROLLBACK ();
792 last_col = TermWin.ncol; 702 last_col = ncol;
793 703
794 if (nlines > 0) 704 if (nlines > 0)
795 { 705 {
796 nlines += screen.cur.row - screen.bscroll; 706 nlines += screen.cur.row - screen.bscroll;
797 if ((nlines > 0) 707 if (nlines > 0
798 && (screen.tscroll == 0) 708 && screen.tscroll == 0
799 && (screen.bscroll == (TermWin.nrow - 1))) 709 && screen.bscroll == (nrow - 1))
800 { 710 {
801 /* _at least_ this many lines need to be scrolled */ 711 /* _at least_ this many lines need to be scrolled */
802 scr_scroll_text (screen.tscroll, screen.bscroll, nlines, 0); 712 scr_scroll_text (screen.tscroll, screen.bscroll, nlines);
803 screen.cur.row -= nlines; 713 screen.cur.row -= nlines;
804 } 714 }
805 } 715 }
806 716
807#ifdef DEBUG_STRICT 717#ifdef DEBUG_STRICT
808 assert (screen.cur.col < last_col); 718 assert (screen.cur.col < last_col);
809 assert ((screen.cur.row < TermWin.nrow) 719 assert (screen.cur.row < nrow
810 && (screen.cur.row >= - (int32_t)TermWin.nscrolled)); 720 && screen.cur.row >= -nsaved);
811#else /* drive with your eyes closed */
812 MIN_IT (screen.cur.col, last_col - 1);
813 MIN_IT (screen.cur.row, (int32_t)TermWin.nrow - 1);
814 MAX_IT (screen.cur.row, - (int32_t)TermWin.nscrolled);
815#endif 721#endif
816 row = screen.cur.row + TermWin.saveLines; 722 row = screen.cur.row;
817 723
818 checksel = selection.op && current_screen == selection.screen ? 1 : 0; 724 checksel = selection.op && current_screen == selection.screen ? 1 : 0;
819 725
820 stp = screen.text[row]; 726 line_t *line = &ROW(row);
821 srp = screen.rend[row];
822 727
823 while (len--) 728 while (str < strend)
824 { 729 {
825 c = *str++; 730 c = *str++;
826 731
827 if (c < 0x20) 732 if (c < 0x20)
828 switch (c) 733 if (c == C0_LF)
734 {
735 if (!line->is_longer ()) /* XXX: think about this */
736 max_it (line->l, screen.cur.col);
737
738 screen.flags &= ~Screen_WrapNext;
739
740 if (screen.cur.row == screen.bscroll)
741 scr_scroll_text (screen.tscroll, screen.bscroll, 1);
742 else if (screen.cur.row < (nrow - 1))
743 row = ++screen.cur.row;
744
745 line = &ROW(row); /* _must_ refresh */
746 continue;
747 }
748 else if (c == C0_CR)
829 { 749 {
830 case C0_HT: 750 if (!line->is_longer ()) /* XXX: think about this */
831 scr_tab (1); 751 max_it (line->l, screen.cur.col);
832 continue;
833 752
834 case C0_LF:
835 if (screen.tlen[row] != -1) /* XXX: think about this */
836 MAX_IT (screen.tlen[row], screen.cur.col);
837
838 screen.flags &= ~Screen_WrapNext; 753 screen.flags &= ~Screen_WrapNext;
839
840 if (screen.cur.row == screen.bscroll)
841 scr_scroll_text (screen.tscroll, screen.bscroll, 1, 0);
842 else if (screen.cur.row < (TermWin.nrow - 1))
843 row = (++screen.cur.row) + TermWin.saveLines;
844
845 stp = screen.text[row]; /* _must_ refresh */
846 srp = screen.rend[row]; /* _must_ refresh */
847 continue;
848
849 case C0_CR:
850 if (screen.tlen[row] != -1) /* XXX: think about this */
851 MAX_IT (screen.tlen[row], screen.cur.col);
852
853 screen.flags &= ~Screen_WrapNext;
854 screen.cur.col = 0; 754 screen.cur.col = 0;
855 continue; 755 continue;
756 }
757 else if (c == C0_HT)
758 {
759 scr_tab (1, true);
760 continue;
856 } 761 }
857 762
858 if (checksel /* see if we're writing within selection */ 763 if (checksel /* see if we're writing within selection */
859 && !ROWCOL_IS_BEFORE (screen.cur, selection.beg) 764 && !ROWCOL_IS_BEFORE (screen.cur, selection.beg)
860 && ROWCOL_IS_BEFORE (screen.cur, selection.end)) 765 && ROWCOL_IS_BEFORE (screen.cur, selection.end))
868 CLEAR_SELECTION (); 773 CLEAR_SELECTION ();
869 } 774 }
870 775
871 if (screen.flags & Screen_WrapNext) 776 if (screen.flags & Screen_WrapNext)
872 { 777 {
873 screen.tlen[row] = -1; 778 line->set_is_longer ();
874 779
875 scr_do_wrap (); row = screen.cur.row + TermWin.saveLines; 780 scr_do_wrap ();
781
782 row = screen.cur.row;
783 line = &ROW(row); /* _must_ refresh */
784 }
876 785
877 stp = screen.text[row]; /* _must_ refresh */ 786 // some utf-8 decoders "decode" surrogate characters: let's fix this.
878 srp = screen.rend[row]; /* _must_ refresh */ 787 if (IN_RANGE_INC (c, 0xd800, 0xdfff))
788 c = 0xfffd;
789
790 // rely on wcwidth to tell us the character width, at least for non-latin1
791 // do wcwidth before further replacements, as wcwidth might return -1
792 // for the line drawing characters below as they might be invalid in the current
793 // locale.
794 int width = c < 0x100 ? 1 : wcwidth (c);
795
796 if (charsets[screen.charset] == '0') // DEC SPECIAL
797 {
798 // vt100 special graphics and line drawing
799 // 5f-7e standard vt100
800 // 40-5e rxvt extension for extra curses acs chars
801 static uint16_t vt100_0[62] = { // 41 .. 7e
802 0x2191, 0x2193, 0x2192, 0x2190, 0x2588, 0x259a, 0x2603, // 41-47 hi mr. snowman!
803 0, 0, 0, 0, 0, 0, 0, 0, // 48-4f
804 0, 0, 0, 0, 0, 0, 0, 0, // 50-57
805 0, 0, 0, 0, 0, 0, 0, 0x0020, // 58-5f
806 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1, // 60-67
807 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba, // 68-6f
808 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, // 70-77
809 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, // 78-7e
810 };
811
812 if (c >= 0x41 && c <= 0x7e && vt100_0[c - 0x41])
813 {
814 c = vt100_0[c - 0x41];
815 width = 1; // vt100 line drawing characters are always single-width
816 }
879 } 817 }
880 818
881 if (screen.flags & Screen_Insert) 819 if (screen.flags & Screen_Insert)
882 scr_insdel_chars (1, INSERT); 820 scr_insdel_chars (width, INSERT);
883
884 // rely on wcwidth to tell us the character width, at least for non-latin1
885 // do wcwidth before further replacements, as wcwidth says that line-drawing
886 // characters have width -1 (DOH!) on GNU/Linux sometimes.
887 int width = c < 0x100 ? 1 : wcwidth (c);
888
889 if (charsets[screen.charset] == '0') // DEC SPECIAL
890 {
891 // vt100 special graphics and line drawing
892 static uint16_t vt100_0[32] = { // 5f .. 7e
893 0x0020, 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0,
894 0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c,
895 0x23ba, 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534,
896 0x252c, 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7,
897 };
898
899 if (c >= 0x5f && c <= 0x7e)
900 {
901 c = vt100_0[c - 0x5f];
902 width = 1;
903 }
904 }
905 821
906 if (width != 0) 822 if (width != 0)
907 { 823 {
908#if !UNICODE_3 824#if !UNICODE_3
909 // trim characters we can't store directly :( 825 // trim characters we can't store directly :(
912 c = rxvt_composite.compose (c); // map to lower 16 bits 828 c = rxvt_composite.compose (c); // map to lower 16 bits
913# else 829# else
914 c = 0xfffd; 830 c = 0xfffd;
915# endif 831# endif
916#endif 832#endif
917 bool bold = (options & Opt_realBold) && ((rstyle & RS_Bold) != 0); 833
918 rend_t rend = SET_FONT (rstyle, 834 // nuke the character at this position, if required
919 c > 0x7f || bold || c < 0x20 835 if (line->t[screen.cur.col] == NOCHAR
920 ? TermWin.fontset->find_font (c, bold) 836 || (screen.cur.col < ncol - 1
921 : TermWin.ascii_map [c - 0x20]); 837 && line->t[screen.cur.col + 1] == NOCHAR))
838 {
839 int col = screen.cur.col;
840
841 // find begin
842 while (col > 0 && line->t[col] == NOCHAR)
843 col--;
844
845 rend_t rend = SET_FONT (line->r[col], FONTSET (line->r[col])->find_font (' '));
846
847 // found begin, nuke
848 do {
849 line->t[col] = ' ';
850 line->r[col] = rend;
851 col++;
852 } while (col < ncol && line->t[col] == NOCHAR);
853 }
854
855 rend_t rend = SET_FONT (rstyle, FONTSET (rstyle)->find_font (c));
856
857 // if the character doesn't fit into the remaining columns...
858 if (screen.cur.col > last_col - width && last_col >= width)
859 {
860 // ...output spaces
861 c = ' ';
862 // and try the same character next loop iteration
863 --str;
864 }
922 865
923 do 866 do
924 { 867 {
925 stp[screen.cur.col] = c; 868 line->t[screen.cur.col] = c;
926 srp[screen.cur.col] = rend; 869 line->r[screen.cur.col] = rend;
927 870
928 if (screen.cur.col < last_col - 1) 871 if (screen.cur.col < last_col - 1)
929 screen.cur.col++; 872 screen.cur.col++;
930 else 873 else
931 { 874 {
932 screen.tlen[row] = last_col; 875 line->l = last_col;
933 if (screen.flags & Screen_Autowrap) 876 if (screen.flags & Screen_Autowrap)
934 screen.flags |= Screen_WrapNext; 877 screen.flags |= Screen_WrapNext;
935 break; 878 break;
936 } 879 }
937 880
938 c = NOCHAR; 881 c = NOCHAR;
939 } 882 }
940 while (--width > 0); 883 while (--width > 0);
941 884
942 // pad with spaces when overwriting wide character with smaller one 885 // pad with spaces when overwriting wide character with smaller one
886 if (!width)
943 for (int c = screen.cur.col; c < last_col && stp[c] == NOCHAR; c++) 887 for (int c = screen.cur.col; c < last_col && line->t[c] == NOCHAR; c++)
944 { 888 {
945 stp[c] = ' '; 889 line->t[c] = ' ';
946 srp[c] = rend; 890 line->r[c] = rend;
947 } 891 }
948 } 892 }
949 else if (width == 0) 893 else // width == 0
950 { 894 {
951#if ENABLE_COMBINING 895#if ENABLE_COMBINING
952 // handle combining characters 896 // handle combining characters
953 // we just tag the accent on the previous on-screen character. 897 // we just tag the accent on the previous on-screen character.
954 // this is arguably not correct, but also arguably not wrong. 898 // this is arguably not correct, but also arguably not wrong.
955 // we don't handle double-width characters nicely yet. 899 // we don't handle double-width characters nicely yet.
956
957 text_t *tp; 900 text_t *tp;
958 rend_t *rp; 901 rend_t *rp;
959 902
960 if (screen.cur.col > 0) 903 if (screen.cur.col > 0)
961 { 904 {
962 tp = stp + screen.cur.col - 1; 905 tp = line->t + screen.cur.col - 1;
963 rp = srp + screen.cur.col - 1; 906 rp = line->r + screen.cur.col - 1;
907
908 while (*tp == NOCHAR && tp > line->t)
909 tp--, rp--;
964 } 910 }
965 else if (screen.cur.row > 0 911 else if (screen.cur.row > 0
966 && screen.tlen [screen.cur.row - 1 + TermWin.saveLines] == -1) 912 && ROW(screen.cur.row - 1).is_longer ())
967 { 913 {
968 tp = screen.text[screen.cur.row - 1 + TermWin.saveLines] + last_col - 1; 914 line_t *line = &ROW(screen.cur.row - 1);
969 rp = screen.rend[screen.cur.row - 1 + TermWin.saveLines] + last_col - 1; 915
916 tp = line->t + last_col - 1;
917 rp = line->r + last_col - 1;
918
919 while (*tp == NOCHAR && tp > line->t)
920 tp--, rp--;
970 } 921 }
971 else 922 else
972 continue; 923 continue;
973
974 // handle double-width-chars by making them look extremely ugly
975 if (*tp == NOCHAR)
976 *tp = ' '; // hack //D //TODO //--tp, --rp;
977 924
978 // first try to find a precomposed character 925 // first try to find a precomposed character
979 unicode_t n = rxvt_compose (*tp, c); 926 unicode_t n = rxvt_compose (*tp, c);
980 if (n == NOCHAR) 927 if (n == NOCHAR)
981 n = rxvt_composite.compose (*tp, c); 928 n = rxvt_composite.compose (*tp, c);
982 929
983 *tp = n; 930 *tp = n;
984 *rp = SET_FONT (*rp, TermWin.fontset->find_font (*tp)); 931 *rp = SET_FONT (*rp, FONTSET (*rp)->find_font (*tp));
985#endif 932#endif
986 } 933 }
987 } 934 }
988 935
989 if (screen.tlen[row] != -1) /* XXX: think about this */ 936 if (!line->is_longer ()) /* XXX: think about this */
990 MAX_IT (screen.tlen[row], screen.cur.col); 937 max_it (line->l, screen.cur.col);
991 938
992#ifdef DEBUG_STRICT 939#ifdef DEBUG_STRICT
993 assert (screen.cur.row >= 0); 940 assert (screen.cur.row >= 0);
994#else /* drive with your eyes closed */
995 MAX_IT (screen.cur.row, 0);
996#endif 941#endif
997} 942}
998 943
999/* ------------------------------------------------------------------------- */ 944/* ------------------------------------------------------------------------- */
1000/* 945/*
1009 if (screen.cur.col == 0) 954 if (screen.cur.col == 0)
1010 { 955 {
1011 if (screen.cur.row > 0) 956 if (screen.cur.row > 0)
1012 { 957 {
1013#ifdef TERMCAP_HAS_BW 958#ifdef TERMCAP_HAS_BW
1014 screen.cur.col = TermWin.ncol - 1; 959 screen.cur.col = ncol - 1;
1015 screen.cur.row--; 960 screen.cur.row--;
1016 return; 961 return;
1017#endif 962#endif
1018 } 963 }
1019 } 964 }
1028 * Process Horizontal Tab 973 * Process Horizontal Tab
1029 * count: +ve = forward; -ve = backwards 974 * count: +ve = forward; -ve = backwards
1030 * XTERM_SEQ: CTRL-I 975 * XTERM_SEQ: CTRL-I
1031 */ 976 */
1032void 977void
1033rxvt_term::scr_tab (int count) 978rxvt_term::scr_tab (int count, bool ht)
1034{ 979{
1035 int i, x; 980 int i, x;
1036 981
1037 want_refresh = 1; 982 want_refresh = 1;
1038 i = x = screen.cur.col; 983 i = x = screen.cur.col;
1039 984
1040 if (count == 0) 985 if (count == 0)
1041 return; 986 return;
1042 else if (count > 0) 987 else if (count > 0)
1043 { 988 {
989 int row = screen.cur.row;
990
991 line_t &l = ROW(row);
992 rend_t base_rend = l.r[i];
993 ht &= l.t[i] == ' ';
994
1044 for (; ++i < TermWin.ncol; ) 995 for (; ++i < ncol; )
1045 if (tabs[i]) 996 if (tabs[i])
1046 { 997 {
1047 x = i; 998 x = i;
1048 if (!--count) 999 if (!--count)
1049 break; 1000 break;
1050 } 1001 }
1002 else
1003 ht &= l.t[i] == ' '
1004 && RS_SAME (l.r[i], base_rend);
1051 1005
1052 if (count) 1006 if (count)
1053 x = TermWin.ncol - 1; 1007 x = ncol - 1;
1008
1009 // store horizontal tab commands as characters inside the text
1010 // buffer so they can be selected and pasted.
1011 if (ht && options & Opt_pastableTabs)
1012 {
1013 base_rend = SET_FONT (base_rend, 0);
1014
1015 if (!l.is_longer ()) /* XXX: think about this */
1016 max_it (l.l, x);
1017
1018 i = screen.cur.col;
1019
1020 l.t[i] = '\t';
1021 l.r[i] = base_rend;
1022
1023 while (++i < x)
1024 {
1025 l.t[i] = NOCHAR;
1026 l.r[i] = base_rend;
1027 }
1028 }
1054 } 1029 }
1055 else /* if (count < 0) */ 1030 else /* if (count < 0) */
1056 { 1031 {
1057 for (; --i >= 0; ) 1032 for (; --i >= 0; )
1058 if (tabs[i]) 1033 if (tabs[i])
1082rxvt_term::scr_backindex () 1057rxvt_term::scr_backindex ()
1083{ 1058{
1084 if (screen.cur.col > 0) 1059 if (screen.cur.col > 0)
1085 scr_gotorc (0, -1, R_RELATIVE | C_RELATIVE); 1060 scr_gotorc (0, -1, R_RELATIVE | C_RELATIVE);
1086 else 1061 else
1087 {
1088 if (screen.tlen[screen.cur.row + TermWin.saveLines] == 0)
1089 return; /* um, yeah? */
1090
1091 scr_insdel_chars (1, INSERT); 1062 scr_insdel_chars (1, INSERT);
1092 }
1093} 1063}
1094#endif 1064#endif
1095/* ------------------------------------------------------------------------- */ 1065/* ------------------------------------------------------------------------- */
1096/* 1066/*
1097 * Process DEC Forward Index 1067 * Process DEC Forward Index
1101 */ 1071 */
1102#if ENABLE_FRILLS 1072#if ENABLE_FRILLS
1103void 1073void
1104rxvt_term::scr_forwardindex () 1074rxvt_term::scr_forwardindex ()
1105{ 1075{
1106 int row; 1076 int row;
1107 1077
1108 if (screen.cur.col < TermWin.ncol - 1) 1078 if (screen.cur.col < ncol - 1)
1109 scr_gotorc (0, 1, R_RELATIVE | C_RELATIVE); 1079 scr_gotorc (0, 1, R_RELATIVE | C_RELATIVE);
1110 else 1080 else
1111 { 1081 {
1112 row = screen.cur.row + TermWin.saveLines; 1082 row = screen.cur.row;
1113 1083
1114 if (screen.tlen[row] == 0) 1084 if (ROW(row).is_longer ()) //TODO//FIXME//LEN
1115 return; /* um, yeah? */ 1085 ROW(row).l = ncol;
1116 else if (screen.tlen[row] == -1)
1117 screen.tlen[row] = TermWin.ncol;
1118 1086
1119 scr_gotorc (0, 0, R_RELATIVE); 1087 scr_gotorc (0, 0, R_RELATIVE);
1120 scr_insdel_chars (1, DELETE); 1088 scr_insdel_chars (1, DELETE);
1121 scr_gotorc (0, TermWin.ncol - 1, R_RELATIVE); 1089 scr_gotorc (0, ncol - 1, R_RELATIVE);
1122 } 1090 }
1123} 1091}
1124#endif 1092#endif
1125 1093
1126/* ------------------------------------------------------------------------- */ 1094/* ------------------------------------------------------------------------- */
1132{ 1100{
1133 want_refresh = 1; 1101 want_refresh = 1;
1134 ZERO_SCROLLBACK (); 1102 ZERO_SCROLLBACK ();
1135 1103
1136 screen.cur.col = relative & C_RELATIVE ? screen.cur.col + col : col; 1104 screen.cur.col = relative & C_RELATIVE ? screen.cur.col + col : col;
1137 MAX_IT (screen.cur.col, 0); 1105 clamp_it (screen.cur.col, 0, ncol - 1);
1138 MIN_IT (screen.cur.col, (int32_t)TermWin.ncol - 1);
1139 1106
1140 screen.flags &= ~Screen_WrapNext; 1107 screen.flags &= ~Screen_WrapNext;
1141 1108
1142 if (relative & R_RELATIVE) 1109 if (relative & R_RELATIVE)
1143 { 1110 {
1161 else 1128 else
1162 { 1129 {
1163 if (screen.flags & Screen_Relative) 1130 if (screen.flags & Screen_Relative)
1164 { /* relative origin mode */ 1131 { /* relative origin mode */
1165 screen.cur.row = row + screen.tscroll; 1132 screen.cur.row = row + screen.tscroll;
1166 MIN_IT (screen.cur.row, screen.bscroll); 1133 min_it (screen.cur.row, screen.bscroll);
1167 } 1134 }
1168 else 1135 else
1169 screen.cur.row = row; 1136 screen.cur.row = row;
1170 } 1137 }
1171 1138
1172 MAX_IT (screen.cur.row, 0); 1139 clamp_it (screen.cur.row, 0, nrow - 1);
1173 MIN_IT (screen.cur.row, (int32_t)TermWin.nrow - 1);
1174} 1140}
1175 1141
1176/* ------------------------------------------------------------------------- */ 1142/* ------------------------------------------------------------------------- */
1177/* 1143/*
1178 * direction should be UP or DN 1144 * direction should be UP or DN
1189 1155
1190 screen.flags &= ~Screen_WrapNext; 1156 screen.flags &= ~Screen_WrapNext;
1191 1157
1192 if ((screen.cur.row == screen.bscroll && direction == UP) 1158 if ((screen.cur.row == screen.bscroll && direction == UP)
1193 || (screen.cur.row == screen.tscroll && direction == DN)) 1159 || (screen.cur.row == screen.tscroll && direction == DN))
1194 scr_scroll_text (screen.tscroll, screen.bscroll, dirn, 0); 1160 scr_scroll_text (screen.tscroll, screen.bscroll, dirn);
1195 else 1161 else
1196 screen.cur.row += dirn; 1162 screen.cur.row += dirn;
1197 1163
1198 MAX_IT (screen.cur.row, 0); 1164 clamp_it (screen.cur.row, 0, nrow - 1);
1199 MIN_IT (screen.cur.row, (int32_t)TermWin.nrow - 1);
1200 selection_check (0); 1165 selection_check (0);
1201} 1166}
1202 1167
1203/* ------------------------------------------------------------------------- */ 1168/* ------------------------------------------------------------------------- */
1204/* 1169/*
1215 want_refresh = 1; 1180 want_refresh = 1;
1216 ZERO_SCROLLBACK (); 1181 ZERO_SCROLLBACK ();
1217 1182
1218 selection_check (1); 1183 selection_check (1);
1219 1184
1220 row = TermWin.saveLines + screen.cur.row; 1185 row = screen.cur.row;
1186
1221 switch (mode) 1187 switch (mode)
1222 { 1188 {
1223 case 0: /* erase to end of line */ 1189 case 0: /* erase to end of line */
1224 col = screen.cur.col; 1190 col = screen.cur.col;
1225 num = TermWin.ncol - col; 1191 num = ncol - col;
1226 MIN_IT (screen.tlen[row], (int16_t)col); 1192 min_it (ROW(row).l, col);
1227 if (ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur) 1193 if (ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur)
1228 || ROWCOL_IN_ROW_AT_OR_AFTER (selection.end, screen.cur)) 1194 || ROWCOL_IN_ROW_AT_OR_AFTER (selection.end, screen.cur))
1229 CLEAR_SELECTION (); 1195 CLEAR_SELECTION ();
1230 break; 1196 break;
1231 case 1: /* erase to beginning of line */ 1197 case 1: /* erase to beginning of line */
1235 || ROWCOL_IN_ROW_AT_OR_BEFORE (selection.end, screen.cur)) 1201 || ROWCOL_IN_ROW_AT_OR_BEFORE (selection.end, screen.cur))
1236 CLEAR_SELECTION (); 1202 CLEAR_SELECTION ();
1237 break; 1203 break;
1238 case 2: /* erase whole line */ 1204 case 2: /* erase whole line */
1239 col = 0; 1205 col = 0;
1240 num = TermWin.ncol; 1206 num = ncol;
1241 screen.tlen[row] = 0; 1207 ROW(row).l = 0;
1242 if (selection.beg.row <= screen.cur.row 1208 if (selection.beg.row <= screen.cur.row
1243 && selection.end.row >= screen.cur.row) 1209 && selection.end.row >= screen.cur.row)
1244 CLEAR_SELECTION (); 1210 CLEAR_SELECTION ();
1245 break; 1211 break;
1246 default: 1212 default:
1247 return; 1213 return;
1248 } 1214 }
1249 1215
1250 if (screen.text[row]) 1216 scr_blank_line (ROW(row), col, num, rstyle);
1251 scr_blank_line (&screen.text[row][col], &screen.rend[row][col], num, rstyle);
1252 else
1253 scr_blank_screen_mem (screen.text, screen.rend, row, rstyle);
1254} 1217}
1255 1218
1256/* ------------------------------------------------------------------------- */ 1219/* ------------------------------------------------------------------------- */
1257/* 1220/*
1258 * Erase part of whole of the screen 1221 * Erase part of whole of the screen
1262 */ 1225 */
1263void 1226void
1264rxvt_term::scr_erase_screen (int mode) 1227rxvt_term::scr_erase_screen (int mode)
1265{ 1228{
1266 int num; 1229 int num;
1267 int32_t row, row_offset; 1230 int32_t row;
1268 rend_t ren; 1231 rend_t ren;
1269 XGCValues gcvalue; 1232 XGCValues gcvalue;
1270 1233
1271 want_refresh = 1; 1234 want_refresh = 1;
1272 ZERO_SCROLLBACK (); 1235 ZERO_SCROLLBACK ();
1273
1274 row_offset = (int32_t)TermWin.saveLines;
1275 1236
1276 switch (mode) 1237 switch (mode)
1277 { 1238 {
1278 case 0: /* erase to end of screen */ 1239 case 0: /* erase to end of screen */
1279 selection_check (1); 1240 selection_check (1);
1280 scr_erase_line (0); 1241 scr_erase_line (0);
1281 row = screen.cur.row + 1; /* possible OOB */ 1242 row = screen.cur.row + 1; /* possible OOB */
1282 num = TermWin.nrow - row; 1243 num = nrow - row;
1283 break; 1244 break;
1284 case 1: /* erase to beginning of screen */ 1245 case 1: /* erase to beginning of screen */
1285 selection_check (3); 1246 selection_check (3);
1286 scr_erase_line (1); 1247 scr_erase_line (1);
1287 row = 0; 1248 row = 0;
1288 num = screen.cur.row; 1249 num = screen.cur.row;
1289 break; 1250 break;
1290 case 2: /* erase whole screen */ 1251 case 2: /* erase whole screen */
1291 selection_check (3); 1252 selection_check (3);
1292 row = 0; 1253 row = 0;
1293 num = TermWin.nrow; 1254 num = nrow;
1294 break; 1255 break;
1295 default: 1256 default:
1296 return; 1257 return;
1297 } 1258 }
1298 1259
1300 && ((selection.beg.row >= row && selection.beg.row <= row + num) 1261 && ((selection.beg.row >= row && selection.beg.row <= row + num)
1301 || (selection.end.row >= row 1262 || (selection.end.row >= row
1302 && selection.end.row <= row + num))) 1263 && selection.end.row <= row + num)))
1303 CLEAR_SELECTION (); 1264 CLEAR_SELECTION ();
1304 1265
1305 if (row >= TermWin.nrow) /* Out Of Bounds */ 1266 if (row >= nrow) /* Out Of Bounds */
1306 return; 1267 return;
1307 1268
1308 MIN_IT (num, (TermWin.nrow - row)); 1269 min_it (num, nrow - row);
1309 1270
1310 if (rstyle & (RS_RVid | RS_Uline)) 1271 if (rstyle & (RS_RVid | RS_Uline))
1311 ren = (rend_t) ~RS_None; 1272 ren = (rend_t) ~RS_None;
1312 else if (GET_BASEBG (rstyle) == Color_bg) 1273 else if (GET_BASEBG (rstyle) == Color_bg)
1313 { 1274 {
1314 ren = DEFAULT_RSTYLE; 1275 ren = DEFAULT_RSTYLE;
1315 CLEAR_ROWS (row, num); 1276 CLEAR_ROWS (row, num);
1316 } 1277 }
1317 else 1278 else
1318 { 1279 {
1319 ren = (rstyle & (RS_fgMask | RS_bgMask)); 1280 ren = rstyle & (RS_fgMask | RS_bgMask);
1320 gcvalue.foreground = pix_colors[GET_BGCOLOR (rstyle)]; 1281 gcvalue.foreground = pix_colors[GET_BGCOLOR (rstyle)];
1321 XChangeGC (display->display, TermWin.gc, GCForeground, &gcvalue); 1282 XChangeGC (display->display, gc, GCForeground, &gcvalue);
1322 ERASE_ROWS (row, num); 1283 ERASE_ROWS (row, num);
1323 gcvalue.foreground = pix_colors[Color_fg]; 1284 gcvalue.foreground = pix_colors[Color_fg];
1324 XChangeGC (display->display, TermWin.gc, GCForeground, &gcvalue); 1285 XChangeGC (display->display, gc, GCForeground, &gcvalue);
1325 } 1286 }
1326 1287
1327 for (; num--; row++) 1288 for (; num--; row++)
1328 { 1289 {
1329 scr_blank_screen_mem (screen.text, screen.rend, 1290 scr_blank_screen_mem (ROW (row), rstyle);
1330 (unsigned int) (row + row_offset), rstyle); 1291 ROW (row).l = 0;
1331 screen.tlen[row + row_offset] = 0; 1292 scr_blank_line (drawn_buf [row], 0, ncol, ren);
1332 scr_blank_line (drawn_text[row], drawn_rend[row],
1333 (unsigned int)TermWin.ncol, ren);
1334 } 1293 }
1335} 1294}
1295
1296#if ENABLE_FRILLS
1297void
1298rxvt_term::scr_erase_savelines ()
1299{
1300 want_refresh = 1;
1301 ZERO_SCROLLBACK ();
1302
1303 nsaved = 0;
1304}
1305#endif
1336 1306
1337/* ------------------------------------------------------------------------- */ 1307/* ------------------------------------------------------------------------- */
1338/* 1308/*
1339 * Fill the screen with `E's 1309 * Fill the screen with `E's
1340 * XTERM_SEQ: Screen Alignment Test: ESC # 8 1310 * XTERM_SEQ: Screen Alignment Test: ESC # 8
1341 */ 1311 */
1342void 1312void
1343rxvt_term::scr_E () 1313rxvt_term::scr_E ()
1344{ 1314{
1345 int i, j, k; 1315 rend_t fs;
1346 rend_t *r1, fs;
1347 1316
1348 want_refresh = 1; 1317 want_refresh = 1;
1349 ZERO_SCROLLBACK (); 1318 ZERO_SCROLLBACK ();
1350 1319
1351 num_scr_allow = 0; 1320 num_scr_allow = 0;
1352 selection_check (3); 1321 selection_check (3);
1353 1322
1354 fs = SET_FONT (rstyle, TermWin.fontset->find_font ('E')); 1323 fs = SET_FONT (rstyle, FONTSET (rstyle)->find_font ('E'));
1355 for (k = TermWin.saveLines, i = TermWin.nrow; i--; k++) 1324 for (int row = nrow; row--; )
1356 { 1325 {
1357 screen.tlen[k] = TermWin.ncol; /* make the `E's selectable */ 1326 line_t &line = ROW(row);
1327
1358 fill_text (screen.text[k], 'E', TermWin.ncol); 1328 fill_text (line.t, 'E', ncol);
1359 for (r1 = screen.rend[k], j = TermWin.ncol; j--; ) 1329 rend_t *r1 = line.r;
1330
1331 for (int j = ncol; j--; )
1360 *r1++ = fs; 1332 *r1++ = fs;
1333
1334 line.l = ncol; /* make the `E's selectable */
1361 } 1335 }
1362} 1336}
1363 1337
1364/* ------------------------------------------------------------------------- */ 1338/* ------------------------------------------------------------------------- */
1365/* 1339/*
1386 count = end; 1360 count = end;
1387 } 1361 }
1388 1362
1389 scr_do_wrap (); 1363 scr_do_wrap ();
1390 1364
1391 scr_scroll_text (screen.cur.row, screen.bscroll, insdel * count, 0); 1365 scr_scroll_text (screen.cur.row, screen.bscroll, insdel * count);
1392} 1366}
1393 1367
1394/* ------------------------------------------------------------------------- */ 1368/* ------------------------------------------------------------------------- */
1395/* 1369/*
1396 * Insert/Delete <count> characters from the current position 1370 * Insert/Delete <count> characters from the current position
1398void 1372void
1399rxvt_term::scr_insdel_chars (int count, int insdel) 1373rxvt_term::scr_insdel_chars (int count, int insdel)
1400{ 1374{
1401 int col, row; 1375 int col, row;
1402 rend_t tr; 1376 rend_t tr;
1403 text_t *stp;
1404 rend_t *srp;
1405 int16_t *slp;
1406 1377
1407 want_refresh = 1; 1378 want_refresh = 1;
1408 ZERO_SCROLLBACK (); 1379 ZERO_SCROLLBACK ();
1409 1380
1410 if (count <= 0) 1381 if (count <= 0)
1411 return; 1382 return;
1412 1383
1413 scr_do_wrap (); 1384 scr_do_wrap ();
1414 1385
1415 selection_check (1); 1386 selection_check (1);
1416 MIN_IT (count, (TermWin.ncol - screen.cur.col)); 1387 min_it (count, ncol - screen.cur.col);
1417 1388
1418 row = screen.cur.row + TermWin.saveLines;
1419
1420 stp = screen.text[row];
1421 srp = screen.rend[row]; 1389 row = screen.cur.row;
1422 slp = &screen.tlen[row]; 1390
1391 line_t *line = &ROW(row);
1423 1392
1424 switch (insdel) 1393 switch (insdel)
1425 { 1394 {
1426 case INSERT: 1395 case INSERT:
1427 for (col = TermWin.ncol - 1; (col - count) >= screen.cur.col; 1396 for (col = ncol - 1; (col - count) >= screen.cur.col; col--)
1428 col--)
1429 { 1397 {
1430 stp[col] = stp[col - count]; 1398 line->t[col] = line->t[col - count];
1431 srp[col] = srp[col - count]; 1399 line->r[col] = line->r[col - count];
1432 } 1400 }
1433 1401
1434 if (*slp != -1) 1402 if (!line->is_longer ())
1435 { 1403 {
1436 *slp += count; 1404 line->l += count;
1437 MIN_IT (*slp, TermWin.ncol); 1405 min_it (line->l, ncol);
1438 } 1406 }
1439 1407
1440 if (selection.op && current_screen == selection.screen 1408 if (selection.op && current_screen == selection.screen
1441 && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur)) 1409 && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur))
1442 { 1410 {
1443 if (selection.end.row != screen.cur.row 1411 if (selection.end.row != screen.cur.row
1444 || (selection.end.col + count >= TermWin.ncol)) 1412 || (selection.end.col + count >= ncol))
1445 CLEAR_SELECTION (); 1413 CLEAR_SELECTION ();
1446 else 1414 else
1447 { /* shift selection */ 1415 { /* shift selection */
1448 selection.beg.col += count; 1416 selection.beg.col += count;
1449 selection.mark.col += count; /* XXX: yes? */ 1417 selection.mark.col += count; /* XXX: yes? */
1450 selection.end.col += count; 1418 selection.end.col += count;
1451 } 1419 }
1452 } 1420 }
1453 1421
1454 scr_blank_line (& (stp[screen.cur.col]), & (srp[screen.cur.col]), 1422 scr_blank_line (*line, screen.cur.col, count, rstyle);
1455 (unsigned int)count, rstyle);
1456 break; 1423 break;
1457 1424
1458 case ERASE: 1425 case ERASE:
1459 screen.cur.col += count; /* don't worry if > TermWin.ncol */ 1426 screen.cur.col += count; /* don't worry if > ncol */
1460 selection_check (1); 1427 selection_check (1);
1461 screen.cur.col -= count; 1428 screen.cur.col -= count;
1462 scr_blank_line (& (stp[screen.cur.col]), & (srp[screen.cur.col]), 1429 scr_blank_line (*line, screen.cur.col, count, rstyle);
1463 (unsigned int)count, rstyle);
1464 break; 1430 break;
1465 1431
1466 case DELETE: 1432 case DELETE:
1467 tr = srp[TermWin.ncol - 1] & (RS_fgMask | RS_bgMask | RS_baseattrMask); 1433 tr = line->r[ncol - 1] & (RS_fgMask | RS_bgMask | RS_baseattrMask);
1468 1434
1469 for (col = screen.cur.col; (col + count) < TermWin.ncol; col++) 1435 for (col = screen.cur.col; (col + count) < ncol; col++)
1470 { 1436 {
1471 stp[col] = stp[col + count]; 1437 line->t[col] = line->t[col + count];
1472 srp[col] = srp[col + count]; 1438 line->r[col] = line->r[col + count];
1473 } 1439 }
1474 1440
1475 scr_blank_line (& (stp[TermWin.ncol - count]), 1441 scr_blank_line (*line, ncol - count, count, tr);
1476 & (srp[TermWin.ncol - count]),
1477 (unsigned int)count, tr);
1478 1442
1479 if (*slp == -1) /* break line continuation */ 1443 if (line->is_longer ()) /* break line continuation */
1480 *slp = TermWin.ncol; 1444 line->l = ncol;
1481 1445
1482 *slp -= count; 1446 line->l = max (line->l - count, 0);
1483 MAX_IT (*slp, 0);
1484 1447
1485 if (selection.op && current_screen == selection.screen 1448 if (selection.op && current_screen == selection.screen
1486 && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur)) 1449 && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur))
1487 { 1450 {
1488 if (selection.end.row != screen.cur.row 1451 if (selection.end.row != screen.cur.row
1489 || (screen.cur.col >= selection.beg.col - count) 1452 || (screen.cur.col >= selection.beg.col - count)
1490 || selection.end.col >= TermWin.ncol) 1453 || selection.end.col >= ncol)
1491 CLEAR_SELECTION (); 1454 CLEAR_SELECTION ();
1492 else 1455 else
1493 { 1456 {
1494 /* shift selection */ 1457 /* shift selection */
1495 selection.beg.col -= count; 1458 selection.beg.col -= count;
1496 selection.mark.col -= count; /* XXX: yes? */ 1459 selection.mark.col -= count; /* XXX: yes? */
1497 selection.end.col -= count; 1460 selection.end.col -= count;
1498 } 1461 }
1499 } 1462 }
1500 1463
1501 break; 1464 break;
1502 } 1465 }
1508 * XTERM_SEQ: Set region <top> - <bot> inclusive: ESC [ <top> ; <bot> r 1471 * XTERM_SEQ: Set region <top> - <bot> inclusive: ESC [ <top> ; <bot> r
1509 */ 1472 */
1510void 1473void
1511rxvt_term::scr_scroll_region (int top, int bot) 1474rxvt_term::scr_scroll_region (int top, int bot)
1512{ 1475{
1513 MAX_IT (top, 0); 1476 max_it (top, 0);
1514 MIN_IT (bot, (int)TermWin.nrow - 1); 1477 min_it (bot, nrow - 1);
1515 1478
1516 if (top > bot) 1479 if (top > bot)
1517 return; 1480 return;
1518 1481
1519 screen.tscroll = top; 1482 screen.tscroll = top;
1568{ 1531{
1569 if (mode) 1532 if (mode)
1570 screen.flags |= Screen_Relative; 1533 screen.flags |= Screen_Relative;
1571 else 1534 else
1572 screen.flags &= ~Screen_Relative; 1535 screen.flags &= ~Screen_Relative;
1536
1573 scr_gotorc (0, 0, 0); 1537 scr_gotorc (0, 0, 0);
1574} 1538}
1575 1539
1576/* ------------------------------------------------------------------------- */ 1540/* ------------------------------------------------------------------------- */
1577/* 1541/*
1597 */ 1561 */
1598void 1562void
1599rxvt_term::scr_set_tab (int mode) 1563rxvt_term::scr_set_tab (int mode)
1600{ 1564{
1601 if (mode < 0) 1565 if (mode < 0)
1602 memset (tabs, 0, TermWin.ncol * sizeof (char)); 1566 memset (tabs, 0, ncol * sizeof (char));
1603 else if (screen.cur.col < TermWin.ncol) 1567 else if (screen.cur.col < ncol)
1604 tabs[screen.cur.col] = (mode ? 1 : 0); 1568 tabs[screen.cur.col] = (mode ? 1 : 0);
1605} 1569}
1606 1570
1607/* ------------------------------------------------------------------------- */ 1571/* ------------------------------------------------------------------------- */
1608/* 1572/*
1616 XGCValues gcvalue; 1580 XGCValues gcvalue;
1617 1581
1618 if (rvideo != mode) 1582 if (rvideo != mode)
1619 { 1583 {
1620 rvideo = mode; 1584 rvideo = mode;
1621 SWAP_IT (pix_colors[Color_fg], pix_colors[Color_bg], rxvt_color); 1585 ::swap (pix_colors[Color_fg], pix_colors[Color_bg]);
1622#if defined(XPM_BACKGROUND) 1586#if XPM_BACKGROUND
1623 if (bgPixmap.pixmap == None) 1587 if (bgPixmap.pixmap == None)
1624#endif 1588#endif
1625#if defined(TRANSPARENT) 1589#if TRANSPARENT
1626 if (! (options & Opt_transparent) || am_transparent == 0) 1590 if (! (options & Opt_transparent) || am_transparent == 0)
1627#endif 1591#endif
1628 XSetWindowBackground (display->display, TermWin.vt, 1592 XSetWindowBackground (display->display, vt,
1629 pix_colors[Color_bg]); 1593 pix_colors[Color_bg]);
1630 1594
1631 gcvalue.foreground = pix_colors[Color_fg]; 1595 gcvalue.foreground = pix_colors[Color_fg];
1632 gcvalue.background = pix_colors[Color_bg]; 1596 gcvalue.background = pix_colors[Color_bg];
1633 XChangeGC (display->display, TermWin.gc, GCBackground | GCForeground, 1597 XChangeGC (display->display, gc, GCBackground | GCForeground,
1634 &gcvalue); 1598 &gcvalue);
1635 scr_clear (); 1599 scr_clear ();
1636 scr_touch (true); 1600 scr_touch (true);
1637 } 1601 }
1638} 1602}
1685 * XTERM_SEQ: Invoke G2 character set: ESC N 1649 * XTERM_SEQ: Invoke G2 character set: ESC N
1686 * XTERM_SEQ: Invoke G3 character set: ESC O 1650 * XTERM_SEQ: Invoke G3 character set: ESC O
1687 */ 1651 */
1688void 1652void
1689rxvt_term::scr_charset_choose (int set) 1653rxvt_term::scr_charset_choose (int set)
1690 { 1654{
1691 screen.charset = set; 1655 screen.charset = set;
1692 set_font_style (); 1656 set_font_style ();
1693 } 1657}
1694 1658
1695/* ------------------------------------------------------------------------- */ 1659/* ------------------------------------------------------------------------- */
1696/* 1660/*
1697 * Set a font 1661 * Set a font
1698 * XTERM_SEQ: Set G0 character set: ESC ( <C> 1662 * XTERM_SEQ: Set G0 character set: ESC ( <C>
1701 * XTERM_SEQ: Set G3 character set: ESC + <C> 1665 * XTERM_SEQ: Set G3 character set: ESC + <C>
1702 * See set_font_style for possible values for <C> 1666 * See set_font_style for possible values for <C>
1703 */ 1667 */
1704void 1668void
1705rxvt_term::scr_charset_set (int set, unsigned int ch) 1669rxvt_term::scr_charset_set (int set, unsigned int ch)
1706 { 1670{
1707 charsets[set] = (unsigned char)ch; 1671 charsets[set] = (unsigned char)ch;
1708 set_font_style (); 1672 set_font_style ();
1709 } 1673}
1710 1674
1711 1675
1712/* ------------------------------------------------------------------------- * 1676/* ------------------------------------------------------------------------- *
1713 * MAJOR SCREEN MANIPULATION * 1677 * MAJOR SCREEN MANIPULATION *
1714 * ------------------------------------------------------------------------- */ 1678 * ------------------------------------------------------------------------- */
1719bool 1683bool
1720rxvt_term::scr_refresh_rend (rend_t mask, rend_t value) 1684rxvt_term::scr_refresh_rend (rend_t mask, rend_t value)
1721{ 1685{
1722 bool found = false; 1686 bool found = false;
1723 1687
1724 for (int i = 0; i < TermWin.nrow; i++) 1688 for (int i = 0; i < nrow; i++)
1725 { 1689 {
1726 int col = 0; 1690 int col = 0;
1727 rend_t *drp = drawn_rend [i]; 1691 rend_t *drp = drawn_buf[i].r;
1728 1692
1729 for (; col < TermWin.ncol; col++, drp++) 1693 for (; col < ncol; col++, drp++)
1730 if ((*drp & mask) == value) 1694 if ((*drp & mask) == value)
1731 { 1695 {
1732 found = true; 1696 found = true;
1733 *drp = ~value; 1697 *drp = ~value;
1734 } 1698 }
1745 PART_END, 1709 PART_END,
1746 RC_COUNT 1710 RC_COUNT
1747}; 1711};
1748 1712
1749void 1713void
1750rxvt_term::scr_expose (int x, int y, int width, int height, bool refresh) 1714rxvt_term::scr_expose (int x, int y, int ewidth, int eheight, bool refresh)
1751{ 1715{
1752 int i; 1716 int i;
1753 row_col_t rc[RC_COUNT]; 1717 row_col_t rc[RC_COUNT];
1754 1718
1755 if (drawn_text == NULL) /* sanity check */ 1719 if (!drawn_buf) /* sanity check */
1756 return; 1720 return;
1757 1721
1758#ifndef NO_SLOW_LINK_SUPPORT 1722#ifndef NO_SLOW_LINK_SUPPORT
1759 if (refresh_type == FAST_REFRESH && !display->is_local) 1723 if (refresh_type == FAST_REFRESH && !display->is_local)
1760 { 1724 {
1761 y = 0; 1725 y = 0;
1762 height = TermWin.height; 1726 eheight = height;
1763 } 1727 }
1764#endif
1765
1766#ifdef DEBUG_STRICT
1767 x = max (x, 0);
1768 x = min (x, (int)TermWin.width);
1769 y = max (y, 0);
1770 y = min (y, (int)TermWin.height);
1771#endif 1728#endif
1772 1729
1773 /* round down */ 1730 /* round down */
1774 rc[PART_BEG].col = Pixel2Col (x); 1731 rc[PART_BEG].col = Pixel2Col (x);
1775 rc[PART_BEG].row = Pixel2Row (y); 1732 rc[PART_BEG].row = Pixel2Row (y);
1776 /* round up */ 1733 /* round up */
1777 rc[PART_END].col = Pixel2Width (x + width + TermWin.fwidth - 1); 1734 rc[PART_END].col = Pixel2Width (x + ewidth + fwidth - 1);
1778 rc[PART_END].row = Pixel2Row (y + height + TermWin.fheight - 1); 1735 rc[PART_END].row = Pixel2Row (y + eheight + fheight - 1);
1779 1736
1780 /* sanity checks */ 1737 /* sanity checks */
1781 for (i = PART_BEG; i < RC_COUNT; i++) 1738 for (i = PART_BEG; i < RC_COUNT; i++)
1782 { 1739 {
1783 MIN_IT (rc[i].col, TermWin.ncol - 1); 1740 min_it (rc[i].col, ncol - 1);
1784 MIN_IT (rc[i].row, TermWin.nrow - 1); 1741 min_it (rc[i].row, nrow - 1);
1785 } 1742 }
1786 1743
1787 for (i = rc[PART_BEG].row; i <= rc[PART_END].row; i++) 1744 for (i = rc[PART_BEG].row; i <= rc[PART_END].row; i++)
1788 fill_text (&drawn_text[i][rc[PART_BEG].col], 0, rc[PART_END].col - rc[PART_BEG].col + 1); 1745 fill_text (&drawn_buf[i].t[rc[PART_BEG].col], 0, rc[PART_END].col - rc[PART_BEG].col + 1);
1789 1746
1790 if (refresh) 1747 if (refresh)
1791 scr_refresh (SLOW_REFRESH); 1748 scr_refresh (SLOW_REFRESH);
1792} 1749}
1793 1750
1796 * Refresh the entire screen 1753 * Refresh the entire screen
1797 */ 1754 */
1798void 1755void
1799rxvt_term::scr_touch (bool refresh) 1756rxvt_term::scr_touch (bool refresh)
1800{ 1757{
1801 scr_expose (0, 0, TermWin.width, TermWin.height, refresh); 1758 scr_expose (0, 0, width, height, refresh);
1802} 1759}
1803 1760
1804/* ------------------------------------------------------------------------- */ 1761/* ------------------------------------------------------------------------- */
1805/* 1762/*
1806 * Move the display so that the line represented by scrollbar value Y is at 1763 * Move the display so that the line represented by scrollbar value Y is at
1808 */ 1765 */
1809int 1766int
1810rxvt_term::scr_move_to (int y, int len) 1767rxvt_term::scr_move_to (int y, int len)
1811{ 1768{
1812 long p = 0; 1769 long p = 0;
1813 uint16_t oldviewstart; 1770 unsigned int oldviewstart;
1814 1771
1815 oldviewstart = TermWin.view_start; 1772 oldviewstart = view_start;
1816 1773
1817 if (y < len) 1774 if (y < len)
1818 { 1775 {
1819 p = (TermWin.nrow + TermWin.nscrolled) * (len - y) / len; 1776 p = (nrow + nsaved) * (len - y) / len;
1820 p -= (long) (TermWin.nrow - 1); 1777 p -= (long) (nrow - 1);
1821 p = max (p, 0); 1778 p = max (p, 0);
1822 } 1779 }
1823 1780
1824 TermWin.view_start = (uint16_t)min (p, TermWin.nscrolled); 1781 view_start = (unsigned int)min (p, nsaved);
1825 1782
1826 return scr_changeview (oldviewstart); 1783 return scr_changeview (oldviewstart);
1827} 1784}
1828 1785
1829/* ------------------------------------------------------------------------- */ 1786/* ------------------------------------------------------------------------- */
1833 */ 1790 */
1834int 1791int
1835rxvt_term::scr_page (enum page_dirn direction, int nlines) 1792rxvt_term::scr_page (enum page_dirn direction, int nlines)
1836{ 1793{
1837 int n; 1794 int n;
1838 uint16_t oldviewstart; 1795 unsigned int oldviewstart;
1839 1796
1840#ifdef DEBUG_STRICT
1841 assert ((nlines >= 0) && (nlines <= TermWin.nrow));
1842#endif
1843 oldviewstart = TermWin.view_start; 1797 oldviewstart = view_start;
1798
1844 if (direction == UP) 1799 if (direction == UP)
1845 { 1800 {
1846 n = TermWin.view_start + nlines; 1801 n = view_start + nlines;
1847 TermWin.view_start = min (n, TermWin.nscrolled); 1802 view_start = min (n, nsaved);
1848 } 1803 }
1849 else 1804 else
1850 { 1805 {
1851 n = TermWin.view_start - nlines; 1806 n = view_start - nlines;
1852 TermWin.view_start = max (n, 0); 1807 view_start = max (n, 0);
1853 } 1808 }
1809
1854 return scr_changeview (oldviewstart); 1810 return scr_changeview (oldviewstart);
1855} 1811}
1856 1812
1857int 1813int
1858rxvt_term::scr_changeview (uint16_t oldviewstart) 1814rxvt_term::scr_changeview (unsigned int oldviewstart)
1859{ 1815{
1860 if (TermWin.view_start != oldviewstart) 1816 if (view_start != oldviewstart)
1861 { 1817 {
1862 want_refresh = 1; 1818 want_refresh = 1;
1863 num_scr -= (TermWin.view_start - oldviewstart); 1819 num_scr -= (view_start - oldviewstart);
1864 } 1820 }
1865 1821
1866 return (int) (TermWin.view_start - oldviewstart); 1822 return (int) (view_start - oldviewstart);
1867} 1823}
1868 1824
1869/* ------------------------------------------------------------------------- */ 1825/* ------------------------------------------------------------------------- */
1870void 1826void
1871rxvt_term::scr_bell () 1827rxvt_term::scr_bell ()
1872{ 1828{
1873#ifndef NO_BELL 1829#ifndef NO_BELL
1830
1874# ifndef NO_MAPALERT 1831# ifndef NO_MAPALERT
1875# ifdef MAPALERT_OPTION 1832# ifdef MAPALERT_OPTION
1876 if (options & Opt_mapAlert) 1833 if (options & Opt_mapAlert)
1877# endif 1834# endif
1878 XMapWindow (display->display, TermWin.parent[0]); 1835 XMapWindow (display->display, parent[0]);
1879# endif 1836# endif
1837
1880 if (options & Opt_visualBell) 1838 if (options & Opt_visualBell)
1881 { 1839 {
1882 scr_rvideo_mode (!rvideo); /* refresh also done */ 1840 scr_rvideo_mode (!rvideo); /* refresh also done */
1841 rxvt_usleep (VISUAL_BELL_DURATION);
1883 scr_rvideo_mode (!rvideo); /* refresh also done */ 1842 scr_rvideo_mode (!rvideo); /* refresh also done */
1884 } 1843 }
1885 else 1844 else
1886 XBell (display->display, 0); 1845 XBell (display->display, 0);
1846
1887#endif 1847#endif
1888} 1848}
1889 1849
1890/* ------------------------------------------------------------------------- */ 1850/* ------------------------------------------------------------------------- */
1891/* ARGSUSED */ 1851/* ARGSUSED */
1892void 1852void
1893rxvt_term::scr_printscreen (int fullhist) 1853rxvt_term::scr_printscreen (int fullhist)
1894{ 1854{
1895#ifdef PRINTPIPE 1855#ifdef PRINTPIPE
1896 int i, r1, nrows, row_offset; 1856 int nrows, row_start;
1897 FILE *fd; 1857 FILE *fd;
1898 1858
1899 if ((fd = popen_printer ()) == NULL) 1859 if ((fd = popen_printer ()) == NULL)
1900 return; 1860 return;
1901 1861
1902 nrows = TermWin.nrow;
1903 row_offset = TermWin.saveLines;
1904
1905 if (!fullhist) 1862 if (fullhist)
1906 row_offset -= TermWin.view_start; 1863 {
1864 nrows = nrow + nsaved;
1865 row_start = -nsaved;
1866 }
1907 else 1867 else
1908 { 1868 {
1909 nrows += TermWin.nscrolled; 1869 nrows = nrow;
1910 row_offset -= TermWin.nscrolled; 1870 row_start = -view_start;
1911 } 1871 }
1912 1872
1913 wctomb (0, 0); 1873 wctomb (0, 0);
1914 1874
1915 for (r1 = 0; r1 < nrows; r1++) 1875 for (int r1 = 0; r1 < nrows; r1++)
1916 { 1876 {
1917 text_t *tp = screen.text[r1 + row_offset]; 1877 text_t *tp = ROW(r1).t;
1918 int len = screen.tlen[r1 + row_offset]; 1878 int len = ROW(r1).l;
1919 1879
1920 for (i = len >= 0 ? len : TermWin.ncol - 1; i--; ) 1880 for (int i = len >= 0 ? len : ncol - 1; i--; ) //TODO//FIXME//LEN
1921 { 1881 {
1922 char mb[MB_LEN_MAX]; 1882 char mb[MB_LEN_MAX];
1923 text_t t = *tp++; 1883 text_t t = *tp++;
1924 if (t == NOCHAR) 1884 if (t == NOCHAR)
1925 continue; 1885 continue;
1946/* 1906/*
1947 * Refresh the screen 1907 * Refresh the screen
1948 * drawn_text/drawn_rend contain the screen information before the update. 1908 * drawn_text/drawn_rend contain the screen information before the update.
1949 * screen.text/screen.rend contain what the screen will change to. 1909 * screen.text/screen.rend contain what the screen will change to.
1950 */ 1910 */
1951
1952#define FONT_WIDTH(X, Y) \
1953 (X)->per_char[ (Y) - (X)->min_char_or_byte2].width
1954#define FONT_RBEAR(X, Y) \
1955 (X)->per_char[ (Y) - (X)->min_char_or_byte2].rbearing
1956#define FONT_LBEAR(X, Y) \
1957 (X)->per_char[ (Y) - (X)->min_char_or_byte2].lbearing
1958#define IS_FONT_CHAR(X, Y) \
1959 ((Y) >= (X)->min_char_or_byte2 && (Y) <= (X)->max_char_or_byte2)
1960
1961void 1911void
1962rxvt_term::scr_refresh (unsigned char refresh_type) 1912rxvt_term::scr_refresh (unsigned char refresh_type)
1963{ 1913{
1964 unsigned char must_clear, /* use draw_string not draw_image_string */ 1914 unsigned char must_clear, /* use draw_string not draw_image_string */
1965 rvid, /* reverse video this position */
1966 showcursor; /* show the cursor */ 1915 showcursor; /* show the cursor */
1967 int16_t col, row, /* column/row we're processing */ 1916 int16_t col, row, /* column/row we're processing */
1968 ocrow; /* old cursor row */ 1917 ocrow; /* old cursor row */
1969 int i, /* tmp */ 1918 int i; /* tmp */
1970 row_offset; /* basic offset in screen structure */
1971#ifndef NO_CURSORCOLOR 1919#ifndef NO_CURSORCOLOR
1972 rend_t cc1; /* store colours at cursor position (s) */ 1920 rend_t cc1; /* store colours at cursor position (s) */
1973#endif 1921#endif
1974 rend_t *crp; // cursor rendition pointer 1922 rend_t *crp; // cursor rendition pointer
1975 1923
1924 want_refresh = 0; /* screen is current */
1925
1976 if (refresh_type == NO_REFRESH || !TermWin.mapped) 1926 if (refresh_type == NO_REFRESH || !mapped)
1977 return; 1927 return;
1978 1928
1979 /* 1929 /*
1980 * A: set up vars 1930 * A: set up vars
1981 */ 1931 */
1982 must_clear = 0; 1932 must_clear = 0;
1983 refresh_count = 0; 1933 refresh_count = 0;
1984 1934
1985 row_offset = TermWin.saveLines - TermWin.view_start;
1986
1987#ifdef XPM_BACKGROUND 1935#if XPM_BACKGROUND
1988 must_clear |= (bgPixmap.pixmap != None); 1936 must_clear |= bgPixmap.pixmap != None;
1989#endif 1937#endif
1990#ifdef TRANSPARENT 1938#if TRANSPARENT
1991 must_clear |= ((options & Opt_transparent) && am_transparent); 1939 must_clear |= (options & Opt_transparent) && am_transparent;
1992#endif 1940#endif
1993 ocrow = oldcursor.row; /* is there an old outline cursor on screen? */ 1941 ocrow = oldcursor.row; /* is there an old outline cursor on screen? */
1994 1942
1995 /* 1943 /*
1996 * B: reverse any characters which are selected 1944 * B: reverse any characters which are selected
1997 */ 1945 */
1998 scr_reverse_selection (); 1946 scr_reverse_selection ();
1999#if ENABLE_OVERLAY
2000 scr_swap_overlay ();
2001#endif
2002 1947
2003 /* 1948 /*
2004 * C: set the cursor character (s) 1949 * C: set the cursor character (s)
2005 */ 1950 */
2006 { 1951 {
2016 1961
2017 if (showcursor) 1962 if (showcursor)
2018 { 1963 {
2019 int col = screen.cur.col; 1964 int col = screen.cur.col;
2020 1965
2021 while (col && screen.text[screen.cur.row + TermWin.saveLines][col] == NOCHAR) 1966 while (col && ROW(screen.cur.row).t[col] == NOCHAR)
2022 col--; 1967 col--;
2023 1968
2024 crp = &screen.rend[screen.cur.row + TermWin.saveLines][col]; 1969 crp = &ROW(screen.cur.row).r[col];
2025 1970
2026 if (showcursor && TermWin.focus) 1971 if (showcursor && focus)
2027 { 1972 {
1973 if (options & Opt_cursorUnderline)
1974 *crp ^= RS_Uline;
1975 else
1976 {
2028 *crp ^= RS_RVid; 1977 *crp ^= RS_RVid;
1978
2029#ifndef NO_CURSORCOLOR 1979#ifndef NO_CURSORCOLOR
2030 cc1 = *crp & (RS_fgMask | RS_bgMask); 1980 cc1 = *crp & (RS_fgMask | RS_bgMask);
2031 if (ISSET_PIXCOLOR (Color_cursor)) 1981 if (ISSET_PIXCOLOR (Color_cursor))
2032 ccol1 = Color_cursor; 1982 ccol1 = Color_cursor;
2033 else 1983 else
2034#ifdef CURSOR_COLOR_IS_RENDITION_COLOR 1984#ifdef CURSOR_COLOR_IS_RENDITION_COLOR
2035 ccol1 = GET_FGCOLOR (rstyle); 1985 ccol1 = GET_FGCOLOR (rstyle);
2036#else 1986#else
2037 ccol1 = Color_fg; 1987 ccol1 = Color_fg;
2038#endif 1988#endif
2039 if (ISSET_PIXCOLOR (Color_cursor2)) 1989 if (ISSET_PIXCOLOR (Color_cursor2))
2040 ccol2 = Color_cursor2; 1990 ccol2 = Color_cursor2;
2041 else 1991 else
2042#ifdef CURSOR_COLOR_IS_RENDITION_COLOR 1992#ifdef CURSOR_COLOR_IS_RENDITION_COLOR
2043 ccol2 = GET_BGCOLOR (rstyle); 1993 ccol2 = GET_BGCOLOR (rstyle);
2044#else 1994#else
2045 ccol2 = Color_bg; 1995 ccol2 = Color_bg;
2046#endif 1996#endif
2047 *crp = SET_FGCOLOR (*crp, ccol1); 1997 *crp = SET_FGCOLOR (*crp, ccol1);
2048 *crp = SET_BGCOLOR (*crp, ccol2); 1998 *crp = SET_BGCOLOR (*crp, ccol2);
2049#endif 1999#endif
2000 }
2050 } 2001 }
2051 } 2002 }
2052 2003
2053 /* make sure no outline cursor is left around */ 2004 /* make sure no outline cursor is left around */
2054 setoldcursor = 0; 2005 setoldcursor = 0;
2055 if (ocrow != -1) 2006 if (ocrow != -1)
2056 { 2007 {
2057 if (screen.cur.row + TermWin.view_start != ocrow 2008 if (screen.cur.row + view_start != ocrow
2058 || screen.cur.col != oldcursor.col) 2009 || screen.cur.col != oldcursor.col)
2059 { 2010 {
2060 if (ocrow < TermWin.nrow 2011 if (ocrow < nrow
2061 && oldcursor.col < TermWin.ncol) 2012 && oldcursor.col < ncol)
2062 drawn_rend[ocrow][oldcursor.col] ^= (RS_RVid | RS_Uline); 2013 drawn_buf[ocrow].r[oldcursor.col] ^= (RS_RVid | RS_Uline);
2063 2014
2064 if (TermWin.focus || !showcursor) 2015 if (focus || !showcursor)
2065 oldcursor.row = -1; 2016 oldcursor.row = -1;
2066 else 2017 else
2067 setoldcursor = 1; 2018 setoldcursor = 1;
2068 } 2019 }
2069 } 2020 }
2070 else if (!TermWin.focus) 2021 else if (!focus)
2071 setoldcursor = 1; 2022 setoldcursor = 1;
2072 2023
2073 if (setoldcursor) 2024 if (setoldcursor)
2074 { 2025 {
2075 if (screen.cur.row + TermWin.view_start >= TermWin.nrow) 2026 if (screen.cur.row + view_start >= nrow)
2076 oldcursor.row = -1; 2027 oldcursor.row = -1;
2077 else 2028 else
2078 { 2029 {
2079 oldcursor.row = screen.cur.row + TermWin.view_start; 2030 oldcursor.row = screen.cur.row + view_start;
2080 oldcursor.col = screen.cur.col; 2031 oldcursor.col = screen.cur.col;
2081 } 2032 }
2082 } 2033 }
2083 } 2034 }
2084 2035
2085 rend_t *drp, *srp; /* drawn-rend-pointer, screen-rend-pointer */ 2036#if ENABLE_OVERLAY
2086 text_t *dtp, *stp; /* drawn-text-pointer, screen-text-pointer */ 2037 scr_swap_overlay ();
2038#endif
2039
2087#ifndef NO_SLOW_LINK_SUPPORT 2040#ifndef NO_SLOW_LINK_SUPPORT
2088 /* 2041 /*
2089 * D: CopyArea pass - very useful for slower links 2042 * D: CopyArea pass - very useful for slower links
2090 * This has been deliberately kept simple. 2043 * This has been deliberately kept simple.
2091 */ 2044 */
2092 i = num_scr; 2045 i = num_scr;
2093 if (!display->is_local 2046 if (!display->is_local
2094 && refresh_type == FAST_REFRESH && num_scr_allow && i 2047 && refresh_type == FAST_REFRESH && num_scr_allow && num_scr
2095 && abs (i) < TermWin.nrow && !must_clear) 2048 && abs (num_scr) < nrow && !must_clear)
2096 { 2049 {
2097 int16_t nits; 2050 int16_t nits;
2098 int j; 2051 int j;
2099 int len, wlen; 2052 int len, wlen;
2100 2053
2101 j = TermWin.nrow; 2054 j = nrow;
2102 wlen = len = -1; 2055 wlen = len = -1;
2103 row = i > 0 ? 0 : j - 1; 2056 row = i > 0 ? 0 : j - 1;
2104 for (; j-- >= 0; row += (i > 0 ? 1 : -1)) 2057 for (; j-- >= 0; row += (i > 0 ? 1 : -1))
2105 { 2058 {
2106 if (row + i >= 0 && row + i < TermWin.nrow && row + i != ocrow) 2059 if (row + i >= 0 && row + i < nrow && row + i != ocrow)
2107 { 2060 {
2108 text_t *stp = screen.text[row + row_offset]; 2061 line_t s = ROW(row - view_start);
2109 rend_t *srp = screen.rend[row + row_offset];
2110 text_t *dtp = drawn_text[row]; 2062 line_t d = drawn_buf[row];
2111 text_t *dtp2 = drawn_text[row + i]; 2063 line_t d2 = drawn_buf[row + i];
2112 rend_t *drp = drawn_rend[row];
2113 rend_t *drp2 = drawn_rend[row + i];
2114 2064
2115 for (nits = 0, col = TermWin.ncol; col--; ) 2065 for (nits = 0, col = ncol; col--; )
2116 if (stp[col] != dtp2[col] || srp[col] != drp2[col]) 2066 if (s.t[col] != d2.t[col] || s.r[col] != d2.r[col])
2117 nits--; 2067 nits--;
2118 else if (stp[col] != dtp[col] || srp[col] != drp[col]) 2068 else if (s.t[col] != d.t[col] || s.r[col] != d.r[col])
2119 nits++; 2069 nits++;
2120 2070
2121 if (nits > 8) /* XXX: arbitrary choice */ 2071 if (nits > 8) /* XXX: arbitrary choice */
2122 { 2072 {
2123 for (col = TermWin.ncol; col--; ) 2073 for (col = ncol; col--; )
2124 { 2074 {
2125 *dtp++ = *dtp2++; 2075 *d.t++ = *d2.t++;
2126 *drp++ = *drp2++; 2076 *d.r++ = *d2.r++;
2127 } 2077 }
2128 2078
2129 if (len == -1) 2079 if (len == -1)
2130 len = row; 2080 len = row;
2131 2081
2136 2086
2137 if (len != -1) 2087 if (len != -1)
2138 { 2088 {
2139 /* also comes here at end if needed because of >= above */ 2089 /* also comes here at end if needed because of >= above */
2140 if (wlen < len) 2090 if (wlen < len)
2141 SWAP_IT (wlen, len, int); 2091 ::swap (wlen, len);
2142 2092
2143 XCopyArea (display->display, TermWin.vt, TermWin.vt, 2093 XCopyArea (display->display, vt, vt,
2144 TermWin.gc, 0, Row2Pixel (len + i), 2094 gc, 0, Row2Pixel (len + i),
2145 (unsigned int)TermWin_TotalWidth (), 2095 (unsigned int)TermWin_TotalWidth (),
2146 (unsigned int)Height2Pixel (wlen - len + 1), 2096 (unsigned int)Height2Pixel (wlen - len + 1),
2147 0, Row2Pixel (len)); 2097 0, Row2Pixel (len));
2148 len = -1; 2098 len = -1;
2149 } 2099 }
2152#endif 2102#endif
2153 2103
2154 /* 2104 /*
2155 * E: main pass across every character 2105 * E: main pass across every character
2156 */ 2106 */
2157 for (row = 0; row < TermWin.nrow; row++) 2107 for (row = 0; row < nrow; row++)
2158 { 2108 {
2159 text_t *stp = screen.text[row + row_offset]; 2109 text_t *stp = ROW(row - view_start).t;
2160 rend_t *srp = screen.rend[row + row_offset]; 2110 rend_t *srp = ROW(row - view_start).r;
2161 text_t *dtp = drawn_text[row]; 2111 text_t *dtp = drawn_buf[row].t;
2162 rend_t *drp = drawn_rend[row]; 2112 rend_t *drp = drawn_buf[row].r;
2163 2113
2164 /* 2114 /*
2165 * E2: OK, now the real pass 2115 * E2: OK, now the real pass
2166 */ 2116 */
2167 int ypixel = (int)Row2Pixel (row); 2117 int ypixel = (int)Row2Pixel (row);
2168 2118
2169 for (col = 0; col < TermWin.ncol; col++) 2119 for (col = 0; col < ncol; col++)
2170 { 2120 {
2171 /* compare new text with old - if exactly the same then continue */ 2121 /* compare new text with old - if exactly the same then continue */
2172 if (stp[col] == dtp[col] /* Must match characters to skip. */ 2122 if (stp[col] == dtp[col] /* Must match characters to skip. */
2173 && (srp[col] == drp[col] /* Either rendition the same or */ 2123 && (RS_SAME (srp[col], drp[col]) /* Either rendition the same or */
2174 || (stp[col] == ' ' /* space w/ no background change */ 2124 || (stp[col] == ' ' /* space w/ no background change */
2175 && GET_BGATTR (srp[col]) == GET_BGATTR (drp[col])))) 2125 && GET_BGATTR (srp[col]) == GET_BGATTR (drp[col]))))
2176 continue; 2126 continue;
2177 2127
2178 // redraw one or more characters 2128 // redraw one or more characters
2179 2129
2180 // seek to the beginning if wide characters 2130 // seek to the beginning of wide characters
2181 while (stp[col] == NOCHAR && col > 0) 2131 while (stp[col] == NOCHAR && col > 0)
2182 --col; 2132 --col;
2183 2133
2184 rend_t rend = srp[col]; /* screen rendition (target rendtion) */ 2134 rend_t rend = srp[col]; /* screen rendition (target rendtion) */
2185 text_t *text = stp + col; 2135 text_t *text = stp + col;
2188 dtp[col] = stp[col]; 2138 dtp[col] = stp[col];
2189 drp[col] = rend; 2139 drp[col] = rend;
2190 2140
2191 int xpixel = Col2Pixel (col); 2141 int xpixel = Col2Pixel (col);
2192 2142
2193 // this loop looks very messy, it can probably be optimized
2194 // and cleaned a bit by you?
2195 for (i = 0; ++col < TermWin.ncol; ) 2143 for (i = 0; ++col < ncol; )
2196 { 2144 {
2197 if (stp[col] == NOCHAR) 2145 if (stp[col] == NOCHAR)
2198 { 2146 {
2199 dtp[col] = stp[col]; 2147 dtp[col] = stp[col];
2200 drp[col] = rend; 2148 drp[col] = rend;
2202 i++; 2150 i++;
2203 2151
2204 continue; 2152 continue;
2205 } 2153 }
2206 2154
2207 if (rend != srp[col]) 2155 if (!RS_SAME (rend, srp[col]))
2208 break; 2156 break;
2209 2157
2210 count++; 2158 count++;
2211 2159
2212 if (stp[col] != dtp[col] 2160 if (stp[col] != dtp[col]
2213 || srp[col] != drp[col]) 2161 || !RS_SAME (srp[col], drp[col]))
2214 { 2162 {
2215 if (must_clear && (i++ > count / 2)) 2163 if (must_clear && (i++ > count / 2))
2216 break; 2164 break;
2217 2165
2218 dtp[col] = stp[col]; 2166 dtp[col] = stp[col];
2231 count++, i--; 2179 count++, i--;
2232 2180
2233 /* 2181 /*
2234 * Determine the attributes for the string 2182 * Determine the attributes for the string
2235 */ 2183 */
2236 int fid = GET_FONT (rend);
2237 int fore = GET_FGCOLOR (rend); // desired foreground 2184 int fore = GET_FGCOLOR (rend); // desired foreground
2238 int back = GET_BGCOLOR (rend); // desired background 2185 int back = GET_BGCOLOR (rend); // desired background
2239 2186
2240 rend = GET_ATTR (rend); 2187 // only do special processing if any attributes are set, which is rare
2188 if (rend & (RS_Bold | RS_Italic | RS_Uline | RS_RVid | RS_Blink | RS_Careful))
2189 {
2190#if ENABLE_STYLES
2191 // force redraw after "careful" characters to avoid pixel droppings
2192 if (srp[col] & RS_Careful && col < ncol - 1 && 0)
2193 drp[col + 1] = ~srp[col + 1];
2241 2194
2242 rvid = !!(rend & RS_RVid); 2195 // include previous careful character(s) if possible, looks nicer (best effort...)
2196 while (text > stp
2197 && srp[text - stp - 1] & RS_Careful
2198 && RS_SAME (rend, srp[text - stp - 1]))
2199 text--, count++, xpixel -= fwidth;
2200#endif
2201
2202 bool invert = rend & RS_RVid;
2243 2203
2244#ifndef NO_BOLD_UNDERLINE_REVERSE 2204#ifndef NO_BOLD_UNDERLINE_REVERSE
2245 if (rend & RS_Bold && fore == Color_fg && !(options & Opt_realBold)) 2205 if (rend & RS_Bold
2206 && fore == Color_fg)
2246 { 2207 {
2247 if (ISSET_PIXCOLOR (Color_BD)) 2208 if (ISSET_PIXCOLOR (Color_BD))
2248 fore = Color_BD; 2209 fore = Color_BD;
2210# if !ENABLE_STYLES
2249 else 2211 else
2250 rvid = !rvid; 2212 invert = !invert;
2213# endif
2214 }
2215
2216 if (rend & RS_Italic
2217 && fore == Color_fg)
2218 {
2219 if (ISSET_PIXCOLOR (Color_IT))
2220 fore = Color_IT;
2221# if !ENABLE_STYLES
2222 else
2223 invert = !invert;
2224# endif
2225 }
2226
2227 if (rend & RS_Uline && ISSET_PIXCOLOR (Color_UL))
2228 fore = Color_UL;
2229#endif
2230
2231 if (invert)
2232 {
2233 ::swap (fore, back);
2234
2235#ifndef NO_BOLD_UNDERLINE_REVERSE
2236 if (ISSET_PIXCOLOR (Color_RV))
2237 back = Color_RV;
2238
2239 if (fore == back)
2240 {
2241 fore = Color_bg;
2242 back = Color_fg;
2243 }
2244#endif
2245 }
2246
2247#ifdef TEXT_BLINK
2248 if (rend & RS_Blink && (back == Color_bg || fore == Color_bg))
2249 {
2250 if (!text_blink_ev.active)
2251 {
2252 text_blink_ev.start (NOW + TEXT_BLINK_INTERVAL);
2253 hidden_text = 0;
2254 }
2255 else if (hidden_text)
2256 fore = back;
2257 }
2258#endif
2251 } 2259 }
2252
2253 if (rend & RS_Uline)
2254 if (ISSET_PIXCOLOR (Color_UL))
2255 fore = Color_UL;
2256#endif
2257
2258 if (rvid)
2259 {
2260 SWAP_IT (fore, back, int);
2261
2262#ifndef NO_BOLD_UNDERLINE_REVERSE
2263 if (ISSET_PIXCOLOR (Color_RV)
2264# ifndef NO_CURSORCOLOR
2265 && !ISSET_PIXCOLOR (Color_cursor)
2266# endif
2267 )
2268 back = Color_RV;
2269#endif
2270 }
2271
2272#ifdef TEXT_BLINK
2273 if (rend & RS_Blink && (back == Color_bg || fore == Color_bg))
2274 {
2275 if (!text_blink_ev.active)
2276 {
2277 text_blink_ev.start (NOW + TEXT_BLINK_INTERVAL);
2278 hidden_text = 0;
2279 }
2280 else if (hidden_text)
2281 fore = back;
2282 }
2283#endif
2284 2260
2285 /* 2261 /*
2286 * Actually do the drawing of the string here 2262 * Actually do the drawing of the string here
2287 */ 2263 */
2288 rxvt_font *font = (*TermWin.fontset)[fid]; 2264 rxvt_font *font = (*fontset[GET_STYLE (rend)])[GET_FONT (rend)];
2289 2265
2290 if (back == fore) 2266 if (back == fore)
2291 font->clear_rect (*TermWin.drawable, xpixel, ypixel, 2267 font->clear_rect (*drawable, xpixel, ypixel,
2292 TermWin.fwidth * count, TermWin.fheight, 2268 fwidth * count, fheight,
2293 back); 2269 back);
2294 else if (back == Color_bg) 2270 else if (back == Color_bg)
2295 { 2271 {
2296 if (must_clear) 2272 if (must_clear)
2297 { 2273 {
2298 CLEAR_CHARS (xpixel, ypixel, count); 2274 CLEAR_CHARS (xpixel, ypixel, count);
2299 2275
2300 for (i = 0; i < count; i++) /* don't draw empty strings */ 2276 for (i = 0; i < count; i++) /* don't draw empty strings */
2301 if (text[i] != ' ') 2277 if (text[i] != ' ')
2302 { 2278 {
2303 font->draw (*TermWin.drawable, xpixel, ypixel, text, count, fore, -1); 2279 font->draw (*drawable, xpixel, ypixel, text, count, fore, -1);
2304 break; 2280 break;
2305 } 2281 }
2306 } 2282 }
2307 else 2283 else
2308 font->draw (*TermWin.drawable, xpixel, ypixel, text, count, fore, Color_bg); 2284 font->draw (*drawable, xpixel, ypixel, text, count, fore, Color_bg);
2309 } 2285 }
2310 else 2286 else
2311 font->draw (*TermWin.drawable, xpixel, ypixel, text, count, fore, back); 2287 font->draw (*drawable, xpixel, ypixel, text, count, fore, back);
2312 2288
2313 if (rend & RS_Uline && font->descent > 1 && fore != back) 2289 if (rend & RS_Uline && font->descent > 1 && fore != back)
2290 {
2291#if ENABLE_FRILLS
2292 if (ISSET_PIXCOLOR (Color_underline))
2293 XSetForeground (display->display, gc, pix_colors[Color_underline]);
2294 else
2295#endif
2296 XSetForeground (display->display, gc, pix_colors[fore]);
2297
2314 XDrawLine (display->display, drawBuffer, TermWin.gc, 2298 XDrawLine (display->display, drawBuffer, gc,
2315 xpixel, ypixel + font->ascent + 1, 2299 xpixel, ypixel + font->ascent + 1,
2316 xpixel + Width2Pixel (count) - 1, ypixel + font->ascent + 1); 2300 xpixel + Width2Pixel (count) - 1, ypixel + font->ascent + 1);
2301 }
2317 } /* for (col....) */ 2302 } /* for (col....) */
2318 } /* for (row....) */ 2303 } /* for (row....) */
2304
2305#if ENABLE_OVERLAY
2306 scr_swap_overlay ();
2307#endif
2319 2308
2320 /* 2309 /*
2321 * G: cleanup cursor and display outline cursor if necessary 2310 * G: cleanup cursor and display outline cursor if necessary
2322 */ 2311 */
2323 if (showcursor) 2312 if (showcursor)
2324 { 2313 {
2325 if (TermWin.focus) 2314 if (focus)
2315 {
2316 if (options & Opt_cursorUnderline)
2317 *crp ^= RS_Uline;
2318 else
2326 { 2319 {
2327 *crp ^= RS_RVid; 2320 *crp ^= RS_RVid;
2328#ifndef NO_CURSORCOLOR 2321#ifndef NO_CURSORCOLOR
2329 *crp = (*crp & ~ (RS_fgMask | RS_bgMask)) | cc1; 2322 *crp = (*crp & ~ (RS_fgMask | RS_bgMask)) | cc1;
2330#endif 2323#endif
2324 }
2331 } 2325 }
2332 else if (oldcursor.row >= 0) 2326 else if (oldcursor.row >= 0)
2333 { 2327 {
2328 int cursorwidth = 1;
2329 int col = oldcursor.col;
2330
2331 while (col && ROW(screen.cur.row).t[col] == NOCHAR)
2332 col--;
2333
2334 while (col + cursorwidth < ncol
2335 && drawn_buf[oldcursor.row].t[col + cursorwidth] == NOCHAR)
2336 cursorwidth++;
2337
2334#ifndef NO_CURSORCOLOR 2338#ifndef NO_CURSORCOLOR
2335 if (ISSET_PIXCOLOR (Color_cursor)) 2339 if (ISSET_PIXCOLOR (Color_cursor))
2336 XSetForeground (display->display, TermWin.gc, pix_colors[Color_cursor]); 2340 XSetForeground (display->display, gc, pix_colors[Color_cursor]);
2337#endif 2341#endif
2338 int cursorwidth = 1;
2339 while (oldcursor.col + cursorwidth < TermWin.ncol
2340 && drawn_text[oldcursor.row][oldcursor.col + cursorwidth] == NOCHAR)
2341 cursorwidth++;
2342 2342
2343 XDrawRectangle (display->display, drawBuffer, TermWin.gc, 2343 XDrawRectangle (display->display, drawBuffer, gc,
2344 Col2Pixel (oldcursor.col), 2344 Col2Pixel (col),
2345 Row2Pixel (oldcursor.row), 2345 Row2Pixel (oldcursor.row),
2346 (unsigned int) (Width2Pixel (cursorwidth) - 1), 2346 (unsigned int) (Width2Pixel (cursorwidth) - 1),
2347 (unsigned int) (Height2Pixel (1) - TermWin.lineSpace - 1)); 2347 (unsigned int) (Height2Pixel (1) - lineSpace - 1));
2348 } 2348 }
2349 } 2349 }
2350 2350
2351 /* 2351 /*
2352 * H: cleanup selection 2352 * H: cleanup selection
2353 */ 2353 */
2354#if ENABLE_OVERLAY
2355 scr_swap_overlay ();
2356#endif
2357 scr_reverse_selection (); 2354 scr_reverse_selection ();
2358 2355
2359 if (refresh_type & SMOOTH_REFRESH) 2356 if (refresh_type & SMOOTH_REFRESH)
2360 XFlush (display->display); 2357 XFlush (display->display);
2361 2358
2362 num_scr = 0; 2359 num_scr = 0;
2363 num_scr_allow = 1; 2360 num_scr_allow = 1;
2364 want_refresh = 0; /* screen is current */
2365} 2361}
2366 2362
2367void 2363void
2368rxvt_term::scr_remap_chars (text_t *tp, rend_t *rp) 2364rxvt_term::scr_remap_chars (const line_t &l)
2369{ 2365{
2370 if (!rp || !tp) 2366 if (!l.t)
2371 return; 2367 return;
2372 2368
2373 for (int i = TermWin.ncol; i; i--, rp++, tp++) 2369 for (int i = ncol; i--; )
2374 *rp = SET_FONT (*rp, TermWin.fontset->find_font (*tp)); 2370 l.r[i] = SET_FONT (l.r[i], FONTSET (l.r[i])->find_font (l.t[i]));
2375} 2371}
2376 2372
2377void 2373void
2378rxvt_term::scr_remap_chars () 2374rxvt_term::scr_remap_chars ()
2379{ 2375{
2380 for (int i = TermWin.nrow + TermWin.saveLines; i--; ) 2376 for (int i = total_rows; i--; )
2381 scr_remap_chars (screen.text[i], screen.rend[i]); 2377 scr_remap_chars (row_buf [i]);
2382 2378
2383 for (int i = TermWin.nrow; i--; ) 2379 for (int i = nrow; i--; )
2384 {
2385 scr_remap_chars (drawn_text[i], drawn_rend[i]);
2386 scr_remap_chars (swap.text[i], swap.rend[i]);
2387 } 2380 {
2381 scr_remap_chars (drawn_buf [i]);
2382 scr_remap_chars (swap_buf [i]);
2383 }
2384}
2385
2386void
2387rxvt_term::scr_recolour ()
2388{
2389 if (1
2390#if TRANSPARENT
2391 && !am_transparent
2392#endif
2393#if XPM_BACKGROUND
2394 && !bgPixmap.pixmap
2395#endif
2396 )
2397 {
2398 XSetWindowBackground (display->display, parent[0], pix_colors[Color_border]);
2399 XClearWindow (display->display, parent[0]);
2400 XSetWindowBackground (display->display, vt, pix_colors[Color_bg]);
2401#if HAVE_SCROLLBARS
2402 if (scrollBar.win)
2403 {
2404 XSetWindowBackground (display->display, scrollBar.win, pix_colors[Color_border]);
2405 scrollBar.setIdle ();
2406 scrollbar_show (0);
2407 }
2408#endif
2409 }
2410
2411 scr_clear ();
2412 scr_touch (true);
2413 want_refresh = 1;
2388} 2414}
2389 2415
2390/* ------------------------------------------------------------------------- */ 2416/* ------------------------------------------------------------------------- */
2391void 2417void
2392rxvt_term::scr_clear (bool really) 2418rxvt_term::scr_clear (bool really)
2393{ 2419{
2394 if (!TermWin.mapped) 2420 if (!mapped)
2395 return; 2421 return;
2396 2422
2397 num_scr_allow = 0; 2423 num_scr_allow = 0;
2398 want_refresh = 1; 2424 want_refresh = 1;
2399 2425
2400#ifdef TRANSPARENT 2426 if (really)
2401 if ((options & Opt_transparent) && (am_pixmap_trans == 0)) 2427 XClearWindow (display->display, vt);
2402 { 2428}
2403 int i;
2404 2429
2405 if (! (options & Opt_transparent_all)) 2430/* ------------------------------------------------------------------------- */
2406 i = 0; 2431void
2432rxvt_term::scr_reverse_selection ()
2433{
2434 if (selection.op
2435 && current_screen == selection.screen
2436 && selection.end.row >= -view_start)
2437 {
2438 int view_end = -view_start + nrow;
2439 int row, col;
2440
2441#if ENABLE_FRILLS
2442 if (selection.rect)
2443 {
2444 for (row = max (selection.beg.row, -view_start); row <= min (selection.end.row, view_end); row++)
2445 for (rend_t *srp = ROW(row).r, col = selection.beg.col; col < selection.end.col; col++)
2446 srp[col] ^= RS_RVid;
2447 }
2407 else 2448 else
2408 i = (int) (sizeof (TermWin.parent) / sizeof (Window));
2409
2410 while (i--)
2411 if (TermWin.parent[i] != None)
2412 XClearWindow (display->display, TermWin.parent[i]);
2413 }
2414#endif 2449#endif
2415 2450 {
2416 if (really) 2451 if (selection.beg.row >= -view_start)
2417 XClearWindow (display->display, TermWin.vt); 2452 {
2418}
2419
2420/* ------------------------------------------------------------------------- */
2421void
2422rxvt_term::scr_reverse_selection ()
2423{
2424 if (selection.op && current_screen == selection.screen)
2425 {
2426 int end_row = TermWin.saveLines - TermWin.view_start;
2427 int i = selection.beg.row + TermWin.saveLines;
2428 int col, row = selection.end.row + TermWin.saveLines;
2429 rend_t *srp;
2430
2431 if (i >= end_row)
2432 col = selection.beg.col; 2453 col = selection.beg.col;
2454 row = selection.beg.row;
2455 }
2433 else 2456 else
2434 { 2457 {
2435 col = 0; 2458 col = 0;
2436 i = end_row; 2459 row = view_start;
2437 } 2460 }
2438 2461
2439 end_row += TermWin.nrow; 2462 for (; row < min (selection.end.row, view_end); row++, col = 0)
2440 for (; i < row && i < end_row; i++, col = 0) 2463 for (rend_t *srp = ROW(row).r; col < ncol; col++)
2441 for (srp = screen.rend[i]; col < TermWin.ncol; col++)
2442 srp[col] ^= RS_RVid; 2464 srp[col] ^= RS_RVid;
2443 2465
2444 if (i == row && i < end_row) 2466 if (row == selection.end.row)
2445 for (srp = screen.rend[i]; col < selection.end.col; col++) 2467 for (rend_t *srp = ROW(row).r; col < selection.end.col; col++)
2446 srp[col] ^= RS_RVid; 2468 srp[col] ^= RS_RVid;
2469 }
2447 } 2470 }
2448} 2471}
2449 2472
2450/* ------------------------------------------------------------------------- */ 2473/* ------------------------------------------------------------------------- */
2451/* 2474/*
2458{ 2481{
2459 int row, wrote; 2482 int row, wrote;
2460 unsigned int width, towrite; 2483 unsigned int width, towrite;
2461 char r1[] = "\n"; 2484 char r1[] = "\n";
2462 2485
2463 for (row = TermWin.saveLines - TermWin.nscrolled; 2486 for (row = saveLines - nsaved;
2464 row < TermWin.saveLines + TermWin.nrow - 1; row++) 2487 row < saveLines + nrow - 1; row++)
2465 { 2488 {
2466 width = screen.tlen[row] >= 0 ? screen.tlen[row] 2489 width = row_buf[row].l >= 0 ? row_buf[row].l
2467 : TermWin.ncol; 2490 : ncol;
2468 for (towrite = width; towrite; towrite -= wrote) 2491 for (towrite = width; towrite; towrite -= wrote)
2469 { 2492 {
2470 wrote = write (fd, & (screen.text[row][width - towrite]), 2493 wrote = write (fd, & (row_buf[row].t[width - towrite]),
2471 towrite); 2494 towrite);
2472 if (wrote < 0) 2495 if (wrote < 0)
2473 return; /* XXX: death, no report */ 2496 return; /* XXX: death, no report */
2474 } 2497 }
2475 if (screen.tlen[row] >= 0) 2498 if (row_buf[row].l >= 0)
2476 if (write (fd, r1, 1) <= 0) 2499 if (write (fd, r1, 1) <= 0)
2477 return; /* XXX: death, no report */ 2500 return; /* XXX: death, no report */
2478 } 2501 }
2479} 2502}
2480#endif 2503#endif
2481 2504
2482/* ------------------------------------------------------------------------- * 2505/* ------------------------------------------------------------------------- *
2483 * CHARACTER SELECTION * 2506 * CHARACTER SELECTION *
2484 * ------------------------------------------------------------------------- */ 2507 * ------------------------------------------------------------------------- */
2485
2486/*
2487 * -TermWin.nscrolled <= (selection row) <= TermWin.nrow - 1
2488 */
2489void 2508void
2490rxvt_term::selection_check (int check_more) 2509rxvt_term::selection_check (int check_more)
2491{ 2510{
2492 row_col_t pos; 2511 row_col_t pos;
2493 2512
2494 if (!selection.op) 2513 if (!selection.op)
2495 return; 2514 return;
2496 2515
2497 pos.row = pos.col = 0; 2516 pos.row = pos.col = 0;
2498 if ((selection.beg.row < - (int32_t)TermWin.nscrolled) 2517 if (!IN_RANGE_EXC (selection.beg.row, -nsaved, nrow)
2499 || (selection.beg.row >= TermWin.nrow) 2518 || !IN_RANGE_EXC (selection.mark.row, -nsaved, nrow)
2500 || (selection.mark.row < - (int32_t)TermWin.nscrolled) 2519 || !IN_RANGE_EXC (selection.end.row, -nsaved, nrow)
2501 || (selection.mark.row >= TermWin.nrow)
2502 || (selection.end.row < - (int32_t)TermWin.nscrolled)
2503 || (selection.end.row >= TermWin.nrow)
2504 || (check_more == 1 2520 || (check_more == 1
2505 && current_screen == selection.screen 2521 && current_screen == selection.screen
2506 && !ROWCOL_IS_BEFORE (screen.cur, selection.beg) 2522 && !ROWCOL_IS_BEFORE (screen.cur, selection.beg)
2507 && ROWCOL_IS_BEFORE (screen.cur, selection.end)) 2523 && ROWCOL_IS_BEFORE (screen.cur, selection.end))
2508 || (check_more == 2 2524 || (check_more == 2
2510 && ROWCOL_IS_AFTER (selection.end, pos)) 2526 && ROWCOL_IS_AFTER (selection.end, pos))
2511 || (check_more == 3 2527 || (check_more == 3
2512 && ROWCOL_IS_AFTER (selection.end, pos)) 2528 && ROWCOL_IS_AFTER (selection.end, pos))
2513 || (check_more == 4 /* screen width change */ 2529 || (check_more == 4 /* screen width change */
2514 && (selection.beg.row != selection.end.row 2530 && (selection.beg.row != selection.end.row
2515 || selection.end.col > TermWin.ncol))) 2531 || selection.end.col > ncol)))
2516 CLEAR_SELECTION (); 2532 CLEAR_SELECTION ();
2517} 2533}
2518 2534
2519/* ------------------------------------------------------------------------- */ 2535/* ------------------------------------------------------------------------- */
2520/* 2536/*
2521 * Paste a selection direct to the command fd 2537 * Paste a selection direct to the command fd
2522 */ 2538 */
2523void 2539void
2524rxvt_term::paste (const unsigned char *data, unsigned int len) 2540rxvt_term::paste (unsigned char *data, unsigned int len)
2525{ 2541{
2526 unsigned int i, j, n;
2527 unsigned char *ds = (unsigned char *)rxvt_malloc (PROP_SIZE);
2528
2529 /* convert normal newline chars into common keyboard Return key sequence */ 2542 /* convert normal newline chars into common keyboard Return key sequence */
2530 for (i = 0; i < len; i += PROP_SIZE) 2543 for (unsigned int i = 0; i < len; i++)
2531 {
2532 n = min (len - i, PROP_SIZE);
2533 memcpy (ds, data + i, n);
2534
2535 for (j = 0; j < n; j++)
2536 if (ds[j] == C0_LF) 2544 if (data[i] == C0_LF)
2537 ds[j] = C0_CR; 2545 data[i] = C0_CR;
2538 2546
2539 tt_write (ds, (int)n); 2547 tt_write (data, len);
2540 }
2541
2542 free (ds);
2543} 2548}
2544 2549
2545/* ------------------------------------------------------------------------- */ 2550/* ------------------------------------------------------------------------- */
2546/* 2551/*
2547 * Respond to a notification that a primary selection has been sent 2552 * Respond to a notification that a primary selection has been sent
2548 * EXT: SelectionNotify 2553 * EXT: SelectionNotify
2549 */ 2554 */
2550int 2555void
2551rxvt_term::selection_paste (Window win, Atom prop, bool delete_prop) 2556rxvt_term::selection_paste (Window win, Atom prop, bool delete_prop)
2552{ 2557{
2553 long nread = 0;
2554 unsigned long bytes_after;
2555 XTextProperty ct;
2556
2557 if (prop == None) /* check for failed XConvertSelection */ 2558 if (prop == None) /* check for failed XConvertSelection */
2558 { 2559 {
2559 if ((selection_type & Sel_CompoundText)) 2560 if ((selection_type & Sel_CompoundText))
2560 { 2561 {
2561 int selnum = selection_type & Sel_whereMask; 2562 int selnum = selection_type & Sel_whereMask;
2574 selection_request_other (xa[XA_COMPOUND_TEXT], selnum); 2575 selection_request_other (xa[XA_COMPOUND_TEXT], selnum);
2575 else 2576 else
2576 selection_type = 0; 2577 selection_type = 0;
2577 } 2578 }
2578 2579
2579 return 0; 2580 return;
2580 }
2581
2582 for (;;)
2583 { 2581 }
2582
2583 unsigned long bytes_after;
2584 XTextProperty ct;
2585
2586 if (XGetWindowProperty (display->display, win, prop,
2587 0, PROP_SIZE / 4,
2588 delete_prop, AnyPropertyType,
2589 &ct.encoding, &ct.format,
2590 &ct.nitems, &bytes_after,
2591 &ct.value) != Success)
2592 {
2593 ct.value = 0;
2594 goto bailout;
2595 }
2596
2597 if (ct.encoding == None)
2598 goto bailout;
2599
2600 if (bytes_after)
2601 {
2602 // fetch and append remaining data
2603 XTextProperty ct2;
2604
2584 if (XGetWindowProperty (display->display, win, prop, (long) (nread / 4), 2605 if (XGetWindowProperty (display->display, win, prop,
2585 (long) (PROP_SIZE / 4), delete_prop, 2606 ct.nitems / 4, (bytes_after + 3) / 4,
2607 delete_prop, AnyPropertyType,
2586 AnyPropertyType, &ct.encoding, &ct.format, 2608 &ct2.encoding, &ct2.format,
2587 &ct.nitems, &bytes_after, 2609 &ct2.nitems, &bytes_after,
2588 &ct.value) != Success) 2610 &ct2.value) != Success)
2589 break; 2611 goto bailout;
2590 2612
2591 if (ct.encoding == 0) 2613 // realloc should be compatible to XFree, here, and elsewhere, too
2592 break; 2614 ct.value = (unsigned char *)realloc (ct.value, ct.nitems + ct2.nitems + 1);
2615 memcpy (ct.value + ct.nitems, ct2.value, ct2.nitems + 1);
2616 ct.nitems += ct2.nitems;
2593 2617
2618 XFree (ct2.value);
2619 }
2620
2621 if (ct.value == 0)
2622 goto bailout;
2623
2594 if (ct.encoding == xa[XA_INCR]) 2624 if (ct.encoding == xa[XA_INCR])
2595 { 2625 {
2596 // INCR selection, start handshake 2626 // INCR selection, start handshake
2627 if (!delete_prop)
2597 XDeleteProperty (display->display, win, prop); 2628 XDeleteProperty (display->display, win, prop);
2629
2598 selection_wait = Sel_incr; 2630 selection_wait = Sel_incr;
2631 incr_buf_fill = 0;
2599 incr_ev.start (NOW + 10); 2632 incr_ev.start (NOW + 10);
2600 break;
2601 }
2602 2633
2603 if (ct.value == NULL) 2634 goto bailout;
2604 continue; 2635 }
2605 2636
2606 if (ct.nitems == 0) 2637 if (ct.nitems == 0)
2638 {
2639 if (selection_wait == Sel_incr)
2640 {
2641 XFree (ct.value);
2642
2643 // finally complete, now paste the whole thing
2644 selection_wait = Sel_normal;
2645 ct.value = (unsigned char *)incr_buf;
2646 ct.nitems = incr_buf_fill;
2647 incr_buf = 0;
2648 incr_buf_size = 0;
2649 incr_ev.stop ();
2607 { 2650 }
2651 else
2652 {
2608 if (selection_wait == Sel_normal && nread == 0 2653 if (selection_wait == Sel_normal
2609 && (win != display->root || prop != XA_CUT_BUFFER0)) // avoid recursion 2654 && (win != display->root || prop != XA_CUT_BUFFER0)) // avoid recursion
2610 { 2655 {
2611 /* 2656 /*
2612 * pass through again trying CUT_BUFFER0 if we've come from 2657 * pass through again trying CUT_BUFFER0 if we've come from
2613 * XConvertSelection () but nothing was presented 2658 * XConvertSelection () but nothing was presented
2614 */ 2659 */
2615 selection_paste (display->root, XA_CUT_BUFFER0, False); 2660 selection_paste (display->root, XA_CUT_BUFFER0, False);
2616 } 2661 }
2617 2662
2618 nread = -1; /* discount any previous stuff */ 2663 goto bailout;
2619 break; 2664 }
2665 }
2666 else if (selection_wait == Sel_incr)
2667 {
2668 incr_ev.start (NOW + 10);
2669
2670 while (incr_buf_fill + ct.nitems > incr_buf_size)
2620 } 2671 {
2672 incr_buf_size = incr_buf_size ? incr_buf_size * 2 : 128*1024;
2673 incr_buf = (char *)realloc (incr_buf, incr_buf_size);
2674 }
2621 2675
2676 memcpy (incr_buf + incr_buf_fill, ct.value, ct.nitems);
2622 nread += ct.nitems; 2677 incr_buf_fill += ct.nitems;
2623 2678
2679 goto bailout;
2680 }
2681
2624 char **cl; 2682 char **cl;
2625 int cr; 2683 int cr;
2684
2685#if ENABLE_FRILLS
2686 // xlib is horribly broken with respect to UTF8_STRING, and nobody cares to fix it
2687 // so recode it manually
2688 if (ct.encoding == xa[XA_UTF8_STRING])
2689 {
2690 wchar_t *w = rxvt_utf8towcs ((const char *)ct.value, ct.nitems);
2691 char *s = rxvt_wcstombs (w);
2692 free (w);
2693 // TODO: strlen == only the first element will be converted. well...
2694 paste ((unsigned char *)s, strlen (s));
2695 free (s);
2696 }
2697 else
2698#endif
2626 if (XmbTextPropertyToTextList (display->display, &ct, &cl, &cr) >= 0 && cl) 2699 if (XmbTextPropertyToTextList (display->display, &ct, &cl, &cr) >= 0
2627 { 2700 && cl)
2701 {
2628 for (int i = 0; i < cr; i++) 2702 for (int i = 0; i < cr; i++)
2629 paste ((unsigned char *)cl[i], strlen (cl[i])); 2703 paste ((unsigned char *)cl[i], strlen (cl[i]));
2630 2704
2631 XFreeStringList (cl); 2705 XFreeStringList (cl);
2632 } 2706 }
2633 else 2707 else
2634 paste (ct.value, ct.nitems); 2708 paste (ct.value, ct.nitems); // paste raw
2635 2709
2636 if (bytes_after == 0) 2710bailout:
2637 break;
2638
2639 XFree (ct.value);
2640 }
2641
2642 if (ct.value)
2643 XFree (ct.value); 2711 XFree (ct.value);
2644 2712
2645 if (selection_wait == Sel_normal) 2713 if (selection_wait == Sel_normal)
2646 selection_wait = Sel_none; 2714 selection_wait = Sel_none;
2647
2648 return (int)nread;
2649} 2715}
2650 2716
2651void 2717void
2652rxvt_term::incr_cb (time_watcher &w) 2718rxvt_term::incr_cb (time_watcher &w)
2653{ 2719{
2654 selection_wait = Sel_none; 2720 selection_wait = Sel_none;
2655 2721
2722 incr_buf_size = 0;
2723 free (incr_buf);
2724
2656 rxvt_warn ("data loss: timeout on INCR selection paste, ignoring.\n"); 2725 rxvt_warn ("data loss: timeout on INCR selection paste, ignoring.\n");
2657} 2726}
2658 2727
2659/*
2660 * INCR support originally provided by Paul Sheer <psheer@obsidian.co.za>
2661 */
2662void 2728void
2663rxvt_term::selection_property (Window win, Atom prop) 2729rxvt_term::selection_property (Window win, Atom prop)
2664{ 2730{
2665 if (prop == None || selection_wait != Sel_incr) 2731 if (prop == None || selection_wait != Sel_incr)
2666 return; 2732 return;
2667 2733
2668 if (selection_paste (win, prop, 1) > 0) 2734 selection_paste (win, prop, true);
2669 incr_ev.start (NOW + 10);
2670 else
2671 {
2672 selection_wait = Sel_none;
2673 incr_ev.stop ();
2674 }
2675} 2735}
2676 2736
2677/* ------------------------------------------------------------------------- */ 2737/* ------------------------------------------------------------------------- */
2678/* 2738/*
2679 * Request the current selection: 2739 * Request the current selection:
2685 * EXT: button 2 release 2745 * EXT: button 2 release
2686 */ 2746 */
2687void 2747void
2688rxvt_term::selection_request (Time tm, int x, int y) 2748rxvt_term::selection_request (Time tm, int x, int y)
2689{ 2749{
2690 if (x < 0 || x >= TermWin.width || y < 0 || y >= TermWin.height) 2750 if (x < 0 || x >= width || y < 0 || y >= height)
2691 return; /* outside window */ 2751 return; /* outside window */
2692 2752
2693 if (selection.text) 2753 if (selection.text)
2694 { /* internal selection */ 2754 { /* internal selection */
2695 char *str = rxvt_wcstombs (selection.text, selection.len); 2755 char *str = rxvt_wcstombs (selection.text, selection.len);
2713#else 2773#else
2714 selection_type = Sel_CompoundText; 2774 selection_type = Sel_CompoundText;
2715 if (selection_request_other (xa[XA_COMPOUND_TEXT], i)) 2775 if (selection_request_other (xa[XA_COMPOUND_TEXT], i))
2716 return; 2776 return;
2717#endif 2777#endif
2718
2719 } 2778 }
2720 } 2779 }
2721 2780
2722 selection_wait = Sel_none; /* don't loop in rxvt_selection_paste () */ 2781 selection_wait = Sel_none; /* don't loop in selection_paste () */
2723 selection_paste (display->root, XA_CUT_BUFFER0, False); 2782 selection_paste (display->root, XA_CUT_BUFFER0, false);
2724} 2783}
2725 2784
2726int 2785int
2727rxvt_term::selection_request_other (Atom target, int selnum) 2786rxvt_term::selection_request_other (Atom target, int selnum)
2728{ 2787{
2729 Atom sel; 2788 Atom sel;
2730#ifdef DEBUG_SELECT
2731 char *debug_xa_names[] = { "PRIMARY", "SECONDARY", "CLIPBOARD" };
2732#endif
2733 2789
2734 selection_type |= selnum; 2790 selection_type |= selnum;
2735 2791
2736 if (selnum == Sel_Primary) 2792 if (selnum == Sel_Primary)
2737 sel = XA_PRIMARY; 2793 sel = XA_PRIMARY;
2741 sel = xa[XA_CLIPBOARD]; 2797 sel = xa[XA_CLIPBOARD];
2742 2798
2743 if (XGetSelectionOwner (display->display, sel) != None) 2799 if (XGetSelectionOwner (display->display, sel) != None)
2744 { 2800 {
2745 XConvertSelection (display->display, sel, target, xa[XA_VT_SELECTION], 2801 XConvertSelection (display->display, sel, target, xa[XA_VT_SELECTION],
2746 TermWin.vt, selection_request_time); 2802 vt, selection_request_time);
2747 return 1; 2803 return 1;
2748 } 2804 }
2749 2805
2750 return 0; 2806 return 0;
2751} 2807}
2774 * EXT: button 1 or 3 release 2830 * EXT: button 1 or 3 release
2775 */ 2831 */
2776void 2832void
2777rxvt_term::selection_make (Time tm) 2833rxvt_term::selection_make (Time tm)
2778{ 2834{
2779 int i, col, end_col, row, end_row; 2835 int i;
2780 wchar_t *new_selection_text; 2836 wchar_t *new_selection_text;
2781 text_t *t; 2837 text_t *t;
2782 2838
2783 switch (selection.op) 2839 switch (selection.op)
2784 { 2840 {
2797 selection.op = SELECTION_DONE; 2853 selection.op = SELECTION_DONE;
2798 2854
2799 if (selection.clicks == 4) 2855 if (selection.clicks == 4)
2800 return; /* nothing selected, go away */ 2856 return; /* nothing selected, go away */
2801 2857
2802 i = (selection.end.row - selection.beg.row + 1) * (TermWin.ncol + 1); 2858 i = (selection.end.row - selection.beg.row + 1) * (ncol + 1);
2803 new_selection_text = (wchar_t *)rxvt_malloc ((i + 4) * sizeof (wchar_t)); 2859 new_selection_text = (wchar_t *)rxvt_malloc ((i + 4) * sizeof (wchar_t));
2804 2860
2805 col = selection.beg.col;
2806 MAX_IT (col, 0);
2807 row = selection.beg.row + TermWin.saveLines;
2808 end_row = selection.end.row + TermWin.saveLines;
2809 int ofs = 0; 2861 int ofs = 0;
2810 int extra = 0; 2862 int extra = 0;
2811 2863
2864 int col = selection.beg.col;
2865 int row = selection.beg.row;
2866
2867 int end_col;
2868
2812 for (; row <= end_row; row++, col = 0) 2869 for (; row <= selection.end.row; row++, col = 0)
2813 { 2870 {
2814 t = &screen.text[row][col]; 2871#if ENABLE_FRILLS
2815 2872 if (selection.rect)
2816 end_col = screen.tlen[row]; 2873 {
2817 2874 col = selection.beg.col;
2818 if (end_col == -1)
2819 end_col = TermWin.ncol; 2875 end_col = ncol + 1;
2876 }
2877 else
2878#endif
2879 end_col = ROW(row).is_longer () ? ncol : ROW(row).l; //TODO//FIXME//LEN
2820 2880
2821 if (row == end_row) 2881 col = max (col, 0);
2882
2883 if (row == selection.end.row || selection.rect)
2822 MIN_IT (end_col, selection.end.col); 2884 end_col = min (end_col, selection.end.col);
2823 2885
2886 t = ROW(row).t + col;
2824 for (; col < end_col; col++) 2887 for (; col < end_col; col++)
2825 { 2888 {
2826 if (*t == NOCHAR) 2889 if (*t == NOCHAR)
2827 t++; 2890 t++;
2828#if ENABLE_COMBINING 2891#if ENABLE_COMBINING
2844#endif 2907#endif
2845 else 2908 else
2846 new_selection_text[ofs++] = *t++; 2909 new_selection_text[ofs++] = *t++;
2847 } 2910 }
2848 2911
2849 if (screen.tlen[row] != -1 && row != end_row) 2912 if (!ROW(row).is_longer () && row != selection.end.row)
2850 new_selection_text[ofs++] = C0_LF; 2913 new_selection_text[ofs++] = C0_LF;
2851 } 2914 }
2852 2915
2853 if (end_col != selection.end.col) 2916 if (end_col != selection.end.col)
2854 new_selection_text[ofs++] = C0_LF; 2917 new_selection_text[ofs++] = C0_LF;
2865 2928
2866 // we usually allocate much more than necessary, so realloc it smaller again 2929 // we usually allocate much more than necessary, so realloc it smaller again
2867 selection.len = ofs; 2930 selection.len = ofs;
2868 selection.text = (wchar_t *)rxvt_realloc (new_selection_text, (ofs + 1) * sizeof (wchar_t)); 2931 selection.text = (wchar_t *)rxvt_realloc (new_selection_text, (ofs + 1) * sizeof (wchar_t));
2869 2932
2870 XSetSelectionOwner (display->display, XA_PRIMARY, TermWin.vt, tm); 2933 XSetSelectionOwner (display->display, XA_PRIMARY, vt, tm);
2871 if (XGetSelectionOwner (display->display, XA_PRIMARY) == TermWin.vt) 2934 if (XGetSelectionOwner (display->display, XA_PRIMARY) == vt)
2872 display->set_selection_owner (this); 2935 display->set_selection_owner (this);
2873 else 2936 else
2874 rxvt_warn ("can't get primary selection, ignoring.\n"); 2937 rxvt_warn ("can't get primary selection, ignoring.\n");
2875 2938
2876#if 0 2939#if 0
2877 XTextProperty ct; 2940 XTextProperty ct;
2878 2941
2879 if (XwcTextListToTextProperty (display->display, &selection.text, 1, XStringStyle, &ct) >= 0) 2942 if (XwcTextListToTextProperty (display->display, &selection.text, 1, XStringStyle, &ct) >= 0)
2880 { 2943 {
2881 XChangeProperty (display->display, display->root, XA_CUT_BUFFER0, XA_STRING, 8, 2944 set_string_property (XA_CUT_BUFFER0, ct.value, ct.nitems);
2882 PropModeReplace, ct.value, ct.nitems);
2883 XFree (ct.value); 2945 XFree (ct.value);
2884 } 2946 }
2885#endif 2947#endif
2886 2948
2887 selection_time = tm; 2949 selection_time = tm;
2900 2962
2901 selection_start_colrow (Pixel2Col (x), Pixel2Row (y)); 2963 selection_start_colrow (Pixel2Col (x), Pixel2Row (y));
2902 2964
2903 if (clicks == 2 || clicks == 3) 2965 if (clicks == 2 || clicks == 3)
2904 selection_extend_colrow (selection.mark.col, 2966 selection_extend_colrow (selection.mark.col,
2905 selection.mark.row + TermWin.view_start, 2967 selection.mark.row + view_start,
2906 0, /* button 3 */ 2968 0, /* button 3 */
2907 1, /* button press */ 2969 1, /* button press */
2908 0); /* click change */ 2970 0); /* click change */
2909} 2971}
2910 2972
2914 */ 2976 */
2915void 2977void
2916rxvt_term::selection_start_colrow (int col, int row) 2978rxvt_term::selection_start_colrow (int col, int row)
2917{ 2979{
2918 want_refresh = 1; 2980 want_refresh = 1;
2981
2982 selection.mark.row = row - view_start;
2919 selection.mark.col = col; 2983 selection.mark.col = col;
2920 selection.mark.row = row - TermWin.view_start;
2921 2984
2922 MAX_IT (selection.mark.row, - (int32_t)TermWin.nscrolled); 2985 selection.mark.row = clamp (selection.mark.row, -nsaved, nrow - 1);
2923 MIN_IT (selection.mark.row, (int32_t)TermWin.nrow - 1); 2986 selection.mark.col = clamp (selection.mark.col, 0, ncol - 1);
2924 MAX_IT (selection.mark.col, 0);
2925 MIN_IT (selection.mark.col, (int32_t)TermWin.ncol - 1);
2926 2987
2927 while (selection.mark.col > 0 2988 while (selection.mark.col > 0
2928 && screen.text[selection.mark.row + TermWin.saveLines][selection.mark.col] == NOCHAR) 2989 && ROW(selection.mark.row).t[selection.mark.col] == NOCHAR)
2929 --selection.mark.col; 2990 --selection.mark.col;
2930 2991
2931 if (selection.op) 2992 if (selection.op)
2932 { /* clear the old selection */ 2993 { /* clear the old selection */
2933 selection.beg.row = selection.end.row = selection.mark.row; 2994 selection.beg.row = selection.end.row = selection.mark.row;
2957 text_t *stp; 3018 text_t *stp;
2958 rend_t *srp; 3019 rend_t *srp;
2959 3020
2960 if (dirn == UP) 3021 if (dirn == UP)
2961 { 3022 {
2962 bound.row = TermWin.saveLines - TermWin.nscrolled - 1; 3023 bound.row = - nsaved - 1;
2963 bound.col = 0; 3024 bound.col = 0;
2964 dirnadd = -1; 3025 dirnadd = -1;
2965 } 3026 }
2966 else 3027 else
2967 { 3028 {
2968 bound.row = TermWin.saveLines + TermWin.nrow; 3029 bound.row = nrow;
2969 bound.col = TermWin.ncol - 1; 3030 bound.col = ncol - 1;
2970 dirnadd = 1; 3031 dirnadd = 1;
2971 } 3032 }
2972 3033
2973 row = mark->row + TermWin.saveLines; 3034 row = mark->row;
2974 col = mark->col; 3035 col = max (mark->col, 0);
2975 MAX_IT (col, 0); 3036
2976 /* find the edge of a word */ 3037 /* find the edge of a word */
2977 stp = &screen.text[row][col]; 3038 stp = ROW(row).t + col; w1 = DELIMIT_TEXT (*stp);
2978 w1 = DELIMIT_TEXT (*stp); 3039 srp = ROW(row).r + col; w2 = DELIMIT_REND (*srp);
2979
2980 srp = &screen.rend[row][col];
2981 w2 = DELIMIT_REND (*srp);
2982 3040
2983 for (;;) 3041 for (;;)
2984 { 3042 {
2985 for (; col != bound.col; col += dirnadd) 3043 for (; col != bound.col; col += dirnadd)
2986 { 3044 {
2996 break; 3054 break;
2997 } 3055 }
2998 3056
2999 if ((col == bound.col) && (row != bound.row)) 3057 if ((col == bound.col) && (row != bound.row))
3000 { 3058 {
3001 if (screen.tlen[ (row - (dirn == UP ? 1 : 0))] == -1) 3059 if (ROW(row - (dirn == UP ? 1 : 0)).is_longer ())
3002 { 3060 {
3003 trow = row + dirnadd; 3061 trow = row + dirnadd;
3004 tcol = dirn == UP ? TermWin.ncol - 1 : 0; 3062 tcol = dirn == UP ? ncol - 1 : 0;
3005 3063
3006 if (screen.text[trow] == NULL) 3064 if (!ROW(trow).t)
3007 break; 3065 break;
3008 3066
3009 stp = & (screen.text[trow][tcol]); 3067 stp = ROW(trow).t + tcol;
3010 srp = & (screen.rend[trow][tcol]); 3068 srp = ROW(trow).r + tcol;
3011 3069
3012 if (DELIMIT_TEXT (*stp) != w1 || DELIMIT_REND (*srp) != w2) 3070 if (DELIMIT_TEXT (*stp) != w1 || DELIMIT_REND (*srp) != w2)
3013 break; 3071 break;
3014 3072
3015 row = trow; 3073 row = trow;
3023Old_Word_Selection_You_Die: 3081Old_Word_Selection_You_Die:
3024 if (dirn == DN) 3082 if (dirn == DN)
3025 col++; /* put us on one past the end */ 3083 col++; /* put us on one past the end */
3026 3084
3027 /* Poke the values back in */ 3085 /* Poke the values back in */
3028 ret->row = row - TermWin.saveLines; 3086 ret->row = row;
3029 ret->col = col; 3087 ret->col = col;
3030} 3088}
3031 3089
3032/* ------------------------------------------------------------------------- */ 3090/* ------------------------------------------------------------------------- */
3033/* 3091/*
3038 * flag == 2 ==> button 3 motion 3096 * flag == 2 ==> button 3 motion
3039 */ 3097 */
3040void 3098void
3041rxvt_term::selection_extend (int x, int y, int flag) 3099rxvt_term::selection_extend (int x, int y, int flag)
3042{ 3100{
3043 int col, row; 3101 int col = clamp (Pixel2Col (x), 0, ncol);
3044 3102 int row = clamp (Pixel2Row (y), 0, nrow - 1);
3045 col = Pixel2Col (x);
3046 row = Pixel2Row (y);
3047 MAX_IT (row, 0);
3048 MIN_IT (row, (int)TermWin.nrow - 1);
3049 MAX_IT (col, 0);
3050 MIN_IT (col, (int)TermWin.ncol);
3051 3103
3052 /* 3104 /*
3053 * If we're selecting characters (single click) then we must check first 3105 * If we're selecting characters (single click) then we must check first
3054 * if we are at the same place as the original mark. If we are then 3106 * if we are at the same place as the original mark. If we are then
3055 * select nothing. Otherwise, if we're to the right of the mark, you have to 3107 * select nothing. Otherwise, if we're to the right of the mark, you have to
3056 * be _past_ a character for it to be selected. 3108 * be _past_ a character for it to be selected.
3057 */ 3109 */
3058 if (((selection.clicks % 3) == 1) && !flag 3110 if (((selection.clicks % 3) == 1) && !flag
3059 && (col == selection.mark.col 3111 && (col == selection.mark.col
3060 && (row == selection.mark.row + TermWin.view_start))) 3112 && (row == selection.mark.row + view_start)))
3061 { 3113 {
3062 /* select nothing */ 3114 /* select nothing */
3063 selection.beg.row = selection.end.row = 0; 3115 selection.beg.row = selection.end.row = 0;
3064 selection.beg.col = selection.end.col = 0; 3116 selection.beg.col = selection.end.col = 0;
3065 selection.clicks = 4; 3117 selection.clicks = 4;
3080 * Extend the selection to the specified col/row 3132 * Extend the selection to the specified col/row
3081 */ 3133 */
3082void 3134void
3083rxvt_term::selection_extend_colrow (int32_t col, int32_t row, int button3, int buttonpress, int clickchange) 3135rxvt_term::selection_extend_colrow (int32_t col, int32_t row, int button3, int buttonpress, int clickchange)
3084{ 3136{
3085 int16_t ncol = TermWin.ncol;
3086 int end_col;
3087 row_col_t pos; 3137 row_col_t pos;
3088 enum { 3138 enum {
3089 LEFT, RIGHT 3139 LEFT, RIGHT
3090 } closeto = RIGHT; 3140 } closeto = RIGHT;
3091 3141
3092 want_refresh = 1; 3142 want_refresh = 1;
3143
3093 switch (selection.op) 3144 switch (selection.op)
3094 { 3145 {
3095 case SELECTION_INIT: 3146 case SELECTION_INIT:
3096 CLEAR_SELECTION (); 3147 CLEAR_SELECTION ();
3097 selection.op = SELECTION_BEGIN; 3148 selection.op = SELECTION_BEGIN;
3110 selection_start_colrow (col, row); 3161 selection_start_colrow (col, row);
3111 /* FALLTHROUGH */ 3162 /* FALLTHROUGH */
3112 default: 3163 default:
3113 return; 3164 return;
3114 } 3165 }
3166
3115 if (selection.beg.col == selection.end.col 3167 if (selection.beg.col == selection.end.col
3116 && selection.beg.col != selection.mark.col 3168 && selection.beg.col != selection.mark.col
3117 && selection.beg.row == selection.end.row 3169 && selection.beg.row == selection.end.row
3118 && selection.beg.row != selection.mark.row) 3170 && selection.beg.row != selection.mark.row)
3119 { 3171 {
3120 selection.beg.col = selection.end.col = selection.mark.col; 3172 selection.beg.col = selection.end.col = selection.mark.col;
3121 selection.beg.row = selection.end.row = selection.mark.row; 3173 selection.beg.row = selection.end.row = selection.mark.row;
3122 } 3174 }
3123 3175
3124 pos.col = col; 3176 pos.col = col;
3125 pos.row = row; 3177 pos.row = row - view_start;
3126
3127 pos.row -= TermWin.view_start; /* adjust for scroll */
3128 3178
3129 /* 3179 /*
3130 * This is mainly xterm style selection with a couple of differences, mainly 3180 * This is mainly xterm style selection with a couple of differences, mainly
3131 * in the way button3 drag extension works. 3181 * in the way button3 drag extension works.
3132 * We're either doing: button1 drag; button3 press; or button3 drag 3182 * We're either doing: button1 drag; button3 press; or button3 drag
3169 } 3219 }
3170 else 3220 else
3171 { /* button1 drag or button3 drag */ 3221 { /* button1 drag or button3 drag */
3172 if (ROWCOL_IS_AFTER (selection.mark, pos)) 3222 if (ROWCOL_IS_AFTER (selection.mark, pos))
3173 { 3223 {
3174 if ((selection.mark.row == selection.end.row) 3224 if (selection.mark.row == selection.end.row
3175 && (selection.mark.col == selection.end.col) 3225 && selection.mark.col == selection.end.col
3226 && clickchange
3176 && clickchange && selection.clicks == 2) 3227 && selection.clicks == 2)
3177 selection.mark.col--; 3228 selection.mark.col--;
3178 3229
3179 selection.beg.row = pos.row; 3230 selection.beg.row = pos.row;
3180 selection.beg.col = pos.col; 3231 selection.beg.col = pos.col;
3181 selection.end.row = selection.mark.row; 3232 selection.end.row = selection.mark.row;
3190 } 3241 }
3191 } 3242 }
3192 3243
3193 if (selection.clicks == 1) 3244 if (selection.clicks == 1)
3194 { 3245 {
3195 end_col = screen.tlen[selection.beg.row + TermWin.saveLines]; 3246 if (selection.beg.col > ROW(selection.beg.row).l //TODO//FIXME//LEN
3196 3247 && !ROW(selection.beg.row).is_longer ()
3197 if (end_col != -1 && selection.beg.col > end_col) 3248#if ENABLE_FRILLS
3249 && !selection.rect
3250#endif
3198 { 3251 )
3199#if 1
3200 selection.beg.col = ncol; 3252 selection.beg.col = ncol;
3201#else 3253
3202 if (selection.beg.row != selection.end.row) 3254 if (
3203 selection.beg.col = ncol; 3255 selection.end.col > ROW(selection.end.row).l //TODO//FIXME//LEN
3204 else 3256 && !ROW(selection.end.row).is_longer ()
3205 selection.beg.col = selection.mark.col; 3257#if ENABLE_FRILLS
3258 && !selection.rect
3206#endif 3259#endif
3207 } 3260 )
3208
3209 end_col = screen.tlen[selection.end.row + TermWin.saveLines];
3210
3211 if (end_col != -1 && selection.end.col > end_col)
3212 selection.end.col = ncol; 3261 selection.end.col = ncol;
3213 } 3262 }
3214 else if (selection.clicks == 2) 3263 else if (selection.clicks == 2)
3215 { 3264 {
3216 if (ROWCOL_IS_AFTER (selection.end, selection.beg)) 3265 if (ROWCOL_IS_AFTER (selection.end, selection.beg))
3217 selection.end.col--; 3266 selection.end.col--;
3218 3267
3219 selection_delimit_word (UP, & (selection.beg), & (selection.beg));
3220 selection_delimit_word (DN, & (selection.end), & (selection.end)); 3268 selection_delimit_word (UP, &selection.beg, &selection.beg);
3269 selection_delimit_word (DN, &selection.end, &selection.end);
3221 } 3270 }
3222 else if (selection.clicks == 3) 3271 else if (selection.clicks == 3)
3223 { 3272 {
3224#if ENABLE_FRILLS 3273#if ENABLE_FRILLS
3225 if ((options & Opt_tripleclickwords)) 3274 if (options & Opt_tripleclickwords)
3226 { 3275 {
3227 int end_row; 3276 selection_delimit_word (UP, &selection.beg, &selection.beg);
3228 3277
3229 selection_delimit_word (UP, & (selection.beg), & (selection.beg));
3230 end_row = screen.tlen[selection.mark.row + TermWin.saveLines];
3231
3232 for (end_row = selection.mark.row; end_row < TermWin.nrow; end_row++) 3278 for (int end_row = selection.mark.row; end_row < nrow; end_row++)
3233 { 3279 {
3234 end_col = screen.tlen[end_row + TermWin.saveLines]; 3280 if (!ROW(end_row).is_longer ())
3235
3236 if (end_col != -1)
3237 { 3281 {
3238 selection.end.row = end_row; 3282 selection.end.row = end_row;
3239 selection.end.col = end_col; 3283 selection.end.col = ROW(end_row).l;
3240 selection_remove_trailing_spaces (); 3284 selection_remove_trailing_spaces ();
3241 break; 3285 break;
3242 } 3286 }
3243 } 3287 }
3244 } 3288 }
3245 else 3289 else
3246#endif 3290#endif
3247 { 3291 {
3248 if (ROWCOL_IS_AFTER (selection.mark, selection.beg)) 3292 if (ROWCOL_IS_AFTER (selection.mark, selection.beg))
3249 selection.mark.col++; 3293 selection.mark.col++;
3294
3250 selection.beg.col = 0; 3295 selection.beg.col = 0;
3251 selection.end.col = ncol; 3296 selection.end.col = ncol;
3297
3298 // select a complete logical line
3299 while (selection.beg.row > -saveLines
3300 && ROW(selection.beg.row - 1).is_longer ())
3301 selection.beg.row--;
3302
3303 while (selection.end.row < nrow
3304 && ROW(selection.end.row).is_longer ())
3305 selection.end.row++;
3252 } 3306 }
3253 } 3307 }
3254 3308
3255 if (button3 && buttonpress) 3309 if (button3 && buttonpress)
3256 { /* mark may need to be changed */ 3310 { /* mark may need to be changed */
3263 { 3317 {
3264 selection.mark.row = selection.beg.row; 3318 selection.mark.row = selection.beg.row;
3265 selection.mark.col = selection.beg.col; 3319 selection.mark.col = selection.beg.col;
3266 } 3320 }
3267 } 3321 }
3268}
3269 3322
3270#if ENABLE_FRILLS 3323#if ENABLE_FRILLS
3324 if (selection.rect && selection.beg.col > selection.end.col)
3325 ::swap (selection.beg.col, selection.end.col);
3326#endif
3327}
3328
3329#if ENABLE_FRILLS
3271void 3330void
3272rxvt_term::selection_remove_trailing_spaces () 3331rxvt_term::selection_remove_trailing_spaces ()
3273{ 3332{
3274 int32_t end_col, end_row; 3333 int32_t end_col, end_row;
3275 text_t *stp; 3334 text_t *stp;
3276 3335
3277 end_col = selection.end.col; 3336 end_col = selection.end.col;
3278 end_row = selection.end.row; 3337 end_row = selection.end.row;
3338
3279 for ( ; end_row >= selection.beg.row; ) 3339 for (; end_row >= selection.beg.row; )
3280 { 3340 {
3281 stp = screen.text[end_row + TermWin.saveLines]; 3341 stp = ROW(end_row).t;
3342
3282 while (--end_col >= 0) 3343 while (--end_col >= 0)
3283 { 3344 {
3284 if (stp[end_col] != ' ' && stp[end_col] != '\t') 3345 if (stp[end_col] != ' '
3346 && stp[end_col] != '\t'
3347 && stp[end_col] != NOCHAR)
3285 break; 3348 break;
3286 } 3349 }
3350
3287 if (end_col >= 0 3351 if (end_col >= 0
3288 || screen.tlen[end_row - 1 + TermWin.saveLines] != -1) 3352 || !ROW(end_row - 1).is_longer ())
3289 { 3353 {
3290 selection.end.col = end_col + 1; 3354 selection.end.col = end_col + 1;
3291 selection.end.row = end_row; 3355 selection.end.row = end_row;
3292 break; 3356 break;
3293 } 3357 }
3358
3294 end_row--; 3359 end_row--;
3295 end_col = TermWin.ncol; 3360 end_col = ncol;
3296 } 3361 }
3362
3297 if (selection.mark.row > selection.end.row) 3363 if (selection.mark.row > selection.end.row)
3298 { 3364 {
3299 selection.mark.row = selection.end.row; 3365 selection.mark.row = selection.end.row;
3300 selection.mark.col = selection.end.col; 3366 selection.mark.col = selection.end.col;
3301 } 3367 }
3317 selection_extend_colrow (Pixel2Col (x), Pixel2Row (y), 1, 0, 1); 3383 selection_extend_colrow (Pixel2Col (x), Pixel2Row (y), 1, 0, 1);
3318} 3384}
3319 3385
3320/* ------------------------------------------------------------------------- */ 3386/* ------------------------------------------------------------------------- */
3321/* 3387/*
3322 * On some systems, the Atom typedef is 64 bits wide. We need to have a type
3323 * that is exactly 32 bits wide, because a format of 64 is not allowed by
3324 * the X11 protocol.
3325 */
3326typedef CARD32 Atom32;
3327
3328/* ------------------------------------------------------------------------- */
3329/*
3330 * Respond to a request for our current selection 3388 * Respond to a request for our current selection
3331 * EXT: SelectionRequest 3389 * EXT: SelectionRequest
3332 */ 3390 */
3333void 3391void
3334rxvt_term::selection_send (const XSelectionRequestEvent &rq) 3392rxvt_term::selection_send (const XSelectionRequestEvent &rq)
3335{ 3393{
3336 XSelectionEvent ev; 3394 XSelectionEvent ev;
3337 XTextProperty ct; 3395 dDisp;
3338 XICCEncodingStyle style;
3339 Atom target;
3340 3396
3341 ev.type = SelectionNotify; 3397 ev.type = SelectionNotify;
3342 ev.property = None; 3398 ev.property = None;
3343 ev.display = rq.display; 3399 ev.display = rq.display;
3344 ev.requestor = rq.requestor; 3400 ev.requestor = rq.requestor;
3346 ev.target = rq.target; 3402 ev.target = rq.target;
3347 ev.time = rq.time; 3403 ev.time = rq.time;
3348 3404
3349 if (rq.target == xa[XA_TARGETS]) 3405 if (rq.target == xa[XA_TARGETS])
3350 { 3406 {
3351 Atom32 target_list[6]; 3407 Atom target_list[6];
3352 Atom32 *target = target_list; 3408 Atom *target = target_list;
3353 3409
3354 *target++ = (Atom32) xa[XA_TARGETS]; 3410 *target++ = xa[XA_TARGETS];
3355 *target++ = (Atom32) xa[XA_TIMESTAMP]; 3411 *target++ = xa[XA_TIMESTAMP];
3356 *target++ = (Atom32) XA_STRING; 3412 *target++ = XA_STRING;
3357 *target++ = (Atom32) xa[XA_TEXT]; 3413 *target++ = xa[XA_TEXT];
3358 *target++ = (Atom32) xa[XA_COMPOUND_TEXT]; 3414 *target++ = xa[XA_COMPOUND_TEXT];
3359#if X_HAVE_UTF8_STRING 3415#if X_HAVE_UTF8_STRING
3360 *target++ = (Atom32) xa[XA_UTF8_STRING]; 3416 *target++ = xa[XA_UTF8_STRING];
3361#endif 3417#endif
3362 3418
3363 XChangeProperty (display->display, rq.requestor, rq.property, XA_ATOM, 3419 XChangeProperty (disp, rq.requestor, rq.property, XA_ATOM,
3364 (8 * sizeof (target_list[0])), PropModeReplace, 3420 32, PropModeReplace,
3365 (unsigned char *)target_list, 3421 (unsigned char *)target_list, target - target_list);
3366 target - target_list);
3367 ev.property = rq.property; 3422 ev.property = rq.property;
3368 } 3423 }
3369#if TODO // TODO 3424#if TODO // TODO
3370 else if (rq.target == xa[XA_MULTIPLE]) 3425 else if (rq.target == xa[XA_MULTIPLE])
3371 { 3426 {
3372 /* TODO: Handle MULTIPLE */ 3427 /* TODO: Handle MULTIPLE */
3373 } 3428 }
3374#endif 3429#endif
3375 else if (rq.target == xa[XA_TIMESTAMP] && selection.text) 3430 else if (rq.target == xa[XA_TIMESTAMP] && selection.text)
3376 { 3431 {
3377 XChangeProperty (display->display, rq.requestor, rq.property, XA_INTEGER, 3432 XChangeProperty (disp, rq.requestor, rq.property, rq.target,
3378 (8 * sizeof (Time)), PropModeReplace,
3379 (unsigned char *)&selection_time, 1); 3433 32, PropModeReplace, (unsigned char *)&selection_time, 1);
3380 ev.property = rq.property; 3434 ev.property = rq.property;
3381 } 3435 }
3382 else if (rq.target == XA_STRING 3436 else if (rq.target == XA_STRING
3383 || rq.target == xa[XA_TEXT] 3437 || rq.target == xa[XA_TEXT]
3384 || rq.target == xa[XA_COMPOUND_TEXT] 3438 || rq.target == xa[XA_COMPOUND_TEXT]
3385 || rq.target == xa[XA_UTF8_STRING] 3439 || rq.target == xa[XA_UTF8_STRING]
3386 ) 3440 )
3387 { 3441 {
3442 XTextProperty ct;
3443 Atom target = rq.target;
3388 short freect = 0; 3444 short freect = 0;
3389 int selectlen; 3445 int selectlen;
3390 wchar_t *cl; 3446 wchar_t *cl;
3391 3447 enum {
3392 target = rq.target; 3448 enc_string = XStringStyle,
3449 enc_text = XStdICCTextStyle,
3450 enc_compound_text = XCompoundTextStyle,
3451#ifdef X_HAVE_UTF8_STRING
3452 enc_utf8 = XUTF8StringStyle,
3453#else
3454 enc_utf8 = -1,
3455#endif
3456 } style;
3393 3457
3394 if (target == XA_STRING) 3458 if (target == XA_STRING)
3395 // we actually don't do XA_STRING, but who cares, as i18n clients 3459 // we actually don't do XA_STRING, but who cares, as i18n clients
3396 // will ask for another format anyways. 3460 // will ask for another format anyways.
3397 style = XStringStyle; 3461 style = enc_string;
3398 else if (target == xa[XA_TEXT]) 3462 else if (target == xa[XA_TEXT])
3399 style = XStdICCTextStyle; 3463 style = enc_text;
3400 else if (target == xa[XA_COMPOUND_TEXT]) 3464 else if (target == xa[XA_COMPOUND_TEXT])
3401 style = XCompoundTextStyle; 3465 style = enc_compound_text;
3402#if X_HAVE_UTF8_STRING 3466#if ENABLE_FRILLS
3403 else if (target == xa[XA_UTF8_STRING]) 3467 else if (target == xa[XA_UTF8_STRING])
3404 style = XUTF8StringStyle; 3468 style = enc_utf8;
3405#endif 3469#endif
3406 else 3470 else
3407 { 3471 {
3408 target = xa[XA_COMPOUND_TEXT]; 3472 target = xa[XA_COMPOUND_TEXT];
3409 style = XCompoundTextStyle; 3473 style = enc_compound_text;
3410 } 3474 }
3411 3475
3412 if (selection.text) 3476 if (selection.text)
3413 { 3477 {
3414 cl = selection.text; 3478 cl = selection.text;
3418 { 3482 {
3419 cl = L""; 3483 cl = L"";
3420 selectlen = 0; 3484 selectlen = 0;
3421 } 3485 }
3422 3486
3423 // Xwc doesn't handle iso-10646 in wchar_t gracefully, so maybe recode it 3487#if ENABLE_FRILLS
3424 // manually for XUTF8StringStyle. 3488 // xlib is horribly broken with respect to UTF8_STRING, and nobody cares to fix it
3489 // so recode it manually
3490 if (style == enc_utf8)
3491 {
3492 freect = 1;
3493 ct.encoding = target;
3494 ct.format = 8;
3495 ct.value = (unsigned char *)rxvt_wcstoutf8 (cl, selectlen);
3496 ct.nitems = strlen ((char *)ct.value);
3497 }
3498 else
3499#endif
3425 if (XwcTextListToTextProperty (display->display, &cl, 1, style, &ct) >= 0) 3500 if (XwcTextListToTextProperty (disp, &cl, 1, (XICCEncodingStyle) style, &ct) >= 0)
3426 freect = 1; 3501 freect = 1;
3427 else 3502 else
3428 { 3503 {
3429 /* if we failed to convert then send it raw */ 3504 /* if we failed to convert then send it raw */
3430 ct.value = (unsigned char *)cl; 3505 ct.value = (unsigned char *)cl;
3431 ct.nitems = selectlen; 3506 ct.nitems = selectlen;
3507 ct.encoding = target;
3432 } 3508 }
3433 3509
3434 XChangeProperty (display->display, rq.requestor, rq.property, 3510 XChangeProperty (disp, rq.requestor, rq.property,
3435 target, 8, PropModeReplace, 3511 ct.encoding, 8, PropModeReplace,
3436 ct.value, (int)ct.nitems); 3512 ct.value, (int)ct.nitems);
3437 ev.property = rq.property; 3513 ev.property = rq.property;
3438 3514
3439 if (freect) 3515 if (freect)
3440 XFree (ct.value); 3516 XFree (ct.value);
3441 } 3517 }
3442 3518
3443 XSendEvent (display->display, rq.requestor, False, 0L, (XEvent *)&ev); 3519 XSendEvent (disp, rq.requestor, False, 0L, (XEvent *)&ev);
3444} 3520}
3445 3521
3446/* ------------------------------------------------------------------------- * 3522/* ------------------------------------------------------------------------- *
3447 * MOUSE ROUTINES * 3523 * MOUSE ROUTINES *
3448 * ------------------------------------------------------------------------- */ 3524 * ------------------------------------------------------------------------- */
3452 */ 3528 */
3453void 3529void
3454rxvt_term::pixel_position (int *x, int *y) 3530rxvt_term::pixel_position (int *x, int *y)
3455{ 3531{
3456 *x = Pixel2Col (*x); 3532 *x = Pixel2Col (*x);
3457 /* MAX_IT (*x, 0); MIN_IT (*x, (int)TermWin.ncol - 1); */ 3533 /* max_it (*x, 0); min_it (*x, (int)ncol - 1); */
3458 *y = Pixel2Row (*y); 3534 *y = Pixel2Row (*y);
3459 /* MAX_IT (*y, 0); MIN_IT (*y, (int)TermWin.nrow - 1); */ 3535 /* max_it (*y, 0); min_it (*y, (int)nrow - 1); */
3460} 3536}
3461 3537
3462/* ------------------------------------------------------------------------- */ 3538/* ------------------------------------------------------------------------- */
3463#ifdef USE_XIM 3539#ifdef USE_XIM
3464void 3540void
3465rxvt_term::im_set_position (XPoint &pos) 3541rxvt_term::im_set_position (XPoint &pos)
3466{ 3542{
3467 XWindowAttributes xwa; 3543 XWindowAttributes xwa;
3468 3544
3469 XGetWindowAttributes (display->display, TermWin.vt, &xwa); 3545 XGetWindowAttributes (display->display, vt, &xwa);
3470 3546
3471 pos.x = xwa.x + Col2Pixel (screen.cur.col); 3547 pos.x = xwa.x + Col2Pixel (screen.cur.col);
3472 pos.y = xwa.y + Height2Pixel (screen.cur.row) + TermWin.fbase; 3548 pos.y = xwa.y + Height2Pixel (screen.cur.row) + fbase;
3473} 3549}
3474#endif 3550#endif
3475 3551
3476#if ENABLE_OVERLAY 3552#if ENABLE_OVERLAY
3477void 3553void
3478rxvt_term::scr_overlay_new (int x, int y, int w, int h) 3554rxvt_term::scr_overlay_new (int x, int y, int w, int h)
3479{ 3555{
3480 if (TermWin.nrow < 3 || TermWin.ncol < 3) 3556 if (nrow < 3 || ncol < 3)
3481 return; 3557 return;
3482 3558
3483 want_refresh = 1; 3559 want_refresh = 1;
3484 3560
3485 scr_overlay_off (); 3561 scr_overlay_off ();
3486 3562
3487 if (x < 0) x = TermWin.ncol - w; 3563 if (x < 0) x = ncol - w;
3488 if (y < 0) y = TermWin.nrow - h; 3564 if (y < 0) y = nrow - h;
3489 3565
3490 // make space for border 3566 // make space for border
3491 w += 2; MIN_IT (w, TermWin.ncol); 3567 w += 2; min_it (w, ncol);
3492 h += 2; MIN_IT (h, TermWin.nrow); 3568 h += 2; min_it (h, nrow);
3493 3569
3494 x -= 1; MAX_IT (x, 0); 3570 x -= 1; clamp_it (x, 0, ncol - w);
3495 y -= 1; MAX_IT (y, 0); 3571 y -= 1; clamp_it (y, 0, nrow - h);
3496
3497 MIN_IT (x, TermWin.ncol - w);
3498 MIN_IT (y, TermWin.nrow - h);
3499 3572
3500 ov_x = x; ov_y = y; 3573 ov_x = x; ov_y = y;
3501 ov_w = w; ov_h = h; 3574 ov_w = w; ov_h = h;
3502 3575
3503 ov_text = new text_t *[h]; 3576 ov_text = new text_t *[h];
3507 { 3580 {
3508 text_t *tp = ov_text[y] = new text_t[w]; 3581 text_t *tp = ov_text[y] = new text_t[w];
3509 rend_t *rp = ov_rend[y] = new rend_t[w]; 3582 rend_t *rp = ov_rend[y] = new rend_t[w];
3510 3583
3511 text_t t0, t1, t2; 3584 text_t t0, t1, t2;
3512 rend_t r = SET_BGCOLOR (SET_FGCOLOR (RS_None, Color_bg), Color_fg); 3585 rend_t r = OVERLAY_RSTYLE;
3513 3586
3514 if (y == 0) 3587 if (y == 0)
3515 t0 = 0x2554, t1 = 0x2550, t2 = 0x2557; 3588 t0 = 0x2554, t1 = 0x2550, t2 = 0x2557;
3516 else if (y < h - 1) 3589 else if (y < h - 1)
3517 t0 = 0x2551, t1 = 0x0020, t2 = 0x2551; 3590 t0 = 0x2551, t1 = 0x0020, t2 = 0x2551;
3551} 3624}
3552 3625
3553void 3626void
3554rxvt_term::scr_overlay_set (int x, int y, text_t text, rend_t rend) 3627rxvt_term::scr_overlay_set (int x, int y, text_t text, rend_t rend)
3555{ 3628{
3556 if (!ov_text || x >= ov_w - 2 || y >= ov_h) 3629 if (!ov_text || x >= ov_w - 2 || y >= ov_h - 2)
3557 return; 3630 return;
3558 3631
3559 x++, y++; 3632 x++, y++;
3560 3633
3561 ov_text[y][x] = text; 3634 ov_text[y][x] = text;
3568 while (*s) 3641 while (*s)
3569 scr_overlay_set (x++, y, *s++); 3642 scr_overlay_set (x++, y, *s++);
3570} 3643}
3571 3644
3572void 3645void
3646rxvt_term::scr_overlay_set (int x, int y, const wchar_t *s)
3647{
3648 while (*s)
3649 {
3650 text_t t = *s++;
3651 int width = wcwidth (t);
3652
3653 while (width--)
3654 {
3655 scr_overlay_set (x++, y, t);
3656 t = NOCHAR;
3657 }
3658 }
3659}
3660
3661void
3573rxvt_term::scr_swap_overlay () 3662rxvt_term::scr_swap_overlay ()
3574{ 3663{
3575 if (!ov_text) 3664 if (!ov_text)
3576 return; 3665 return;
3577 3666
3578 int row_offset = ov_y + TermWin.saveLines - TermWin.view_start;
3579
3580 // swap screen mem with overlay 3667 // swap screen mem with overlay
3581 for (int y = ov_h; y--; ) 3668 for (int y = ov_h; y--; )
3582 { 3669 {
3583 text_t *t1 = ov_text[y]; 3670 text_t *t1 = ov_text[y];
3584 rend_t *r1 = ov_rend[y]; 3671 rend_t *r1 = ov_rend[y];
3585 3672
3586 text_t *t2 = screen.text[y + row_offset] + ov_x; 3673 text_t *t2 = ROW(y - view_start).t + ov_x;
3587 rend_t *r2 = screen.rend[y + row_offset] + ov_x; 3674 rend_t *r2 = ROW(y - view_start).r + ov_x;
3588 3675
3589 for (int x = ov_w; x--; ) 3676 for (int x = ov_w; x--; )
3590 { 3677 {
3591 text_t t = *t1; *t1++ = *t2; *t2++ = t; 3678 text_t t = *t1; *t1++ = *t2; *t2++ = t;
3592 rend_t r = *r1; *r1++ = *r2; *r2++ = SET_FONT (r, TermWin.fontset->find_font (t, false)); 3679 rend_t r = *r1; *r1++ = *r2; *r2++ = SET_FONT (r, FONTSET (r)->find_font (t));
3593 } 3680 }
3594 } 3681 }
3595} 3682}
3596 3683
3597#endif 3684#endif
3598/* ------------------------------------------------------------------------- */ 3685/* ------------------------------------------------------------------------- */
3686

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines